1. 计算 1 次

  1. # before
  2. if (strlen($nickname) < 6 || strlen($nickname) > 18) {
  3. return $this->setError('昵称长度必须在两到六个个汉字,六到十八个英文之间');
  4. }
  5. # after
  6. $length = strlen($nickname);
  7. if ($length < 6 || $length > 18) {
  8. return $this->setError('昵称长度必须在两到六个个汉字,六到十八个英文之间');
  9. }

2. divide by zero 的问题

优化点:

  • totalCount 是 数值
  • 需要考虑除数为 0 的情况 ```php

    bad

    $totalCount = (clone $SDb)->count(); $overNewRate = (new Number($overCount))->divide((new Number($totalCount))); $overNewRate = round($overNewRate->multiply(100)->getValue(), 2);

good

try { $overNewRate = (new Number($overCount))->divide($totalCount); $overNewRate = round($overNewRate->multiply(100)->getValue(), 2); } catch (\Exception $e) { $overNewRate = 0; }

  1. <a name="MpEMy"></a>
  2. ## 3. 使用 (string) 替代 strval
  3. > Analyzes if PHP4 functions (intval, floatval, doubleval, strval) are used for type casting and generates hints to use PHP5's type casting construction (i.e. '(type) parameter').
  4. ```php
  5. // bad
  6. $input = strval($_POST['name']);
  7. // good
  8. $input = (string) $_POST['name'];

4. 合并 isset 的多重判定

The inspection is advising when multiple ‘isset(…)’ statements can be merged into one

  1. // bad
  2. if (isset($dir['origin']) && isset($dir['doc'])) {
  3. // ...
  4. }
  5. // good
  6. if (isset($dir['origin'], $dir['doc'])) {
  7. // ...
  8. }

5. If 多条件语法的合并

  1. // bad
  2. if ($profile->chid_status === UserProfile::STATUS_FAIL) {
  3. if ($profile->chid_failed_at) {
  4. // ...
  5. }
  6. }
  7. // good
  8. if ($profile->chid_status === UserProfile::STATUS_FAIL && $profile->chid_failed_at) {
  9. // ...
  10. }

6. 引号的使用

对于单纯字符串使用 ', 对于变量和文本进行混排的, 使用 "

  1. // bad
  2. $domain = "domain.com";
  3. $random = str_random(7);
  4. $randomMail = 'prefix_'.$random.'@'.$domain;
  5. // good
  6. $domain = 'domain.com';
  7. $random = str_random(7);
  8. $randomMail = "prefix_{$random}@{$domain}";
  1. 0 => '',

7. empty 使用的时机

  1. // bad
  2. // 来源于订单取消过期
  3. $orders = OrderHunter::
  4. // ...
  5. ->where('created_at', '<', Carbon::now()->subMinutes($minutes))
  6. ->get();
  7. if (!empty($orders)) {
  8. $Play = new Play();
  9. $orders->each(function (OrderHunter $item) use ($Play) {
  10. // ...
  11. });
  12. }
  13. // good
  14. // 因为这里返回的是一个对象. empty 对象会返回的是 true, 当然这种对于实现了 countable 的来说又是另外一种概念
  15. // todo 这里也需要测试
  16. if ($orders->count()) {
  17. $Play = new Play();
  18. $orders->each(function (OrderHunter $item) use ($Play) {
  19. // ...
  20. });
  21. }

8. 数组箭头后不允许换行

  1. 'hunter' => [
  2. 0 => 'lol',
  3. ],

9. If 后的 ; 需要去掉

  1. if (!$info = $Order->info('003200330087', 62, 1)) {
  2. \Log::error($Order->getError());
  3. }

10. 参数等号对齐

  1. $hunter_type = OrderHunter::ORDER_NORMAL;
  2. $subtotal_price = (new Number($price_id ?? 0))->multiply($num)->getValue();

11. 命名空间和 php 开始 <?php 存在于一行内

  1. <?php namespace Order\Tests\Configuration;

12. 删除文件尾部的 ?>

php 文件的典型标记是以 <?php 开头, ?> 结尾。但是在 Zend Framework 中却不推荐在 php 文件末尾加 ?>
因为在<?php ?>之外的任何字符都会被输出到网页上,而之中的却不会。所以在末尾不加 ?> 可以预防 php 文件被恶意加入字符输出到网页。

13. 数组的键名

在 PHP 中, 使用不经单引号包含的字符串作为数组键名是合法的, 但是我们不希望如此 — 键名应该总是由单引号包含而避免引起混淆. 注意这是使用一个字符串, 而不是使用变量做键名的情况

  1. // 错误
  2. $foo = $assoc_array[blah];
  3. // 正确
  4. $foo = $assoc_array['blah'];
  5. // 错误
  6. $foo = $assoc_array["$var"];
  7. // 正确
  8. $foo = $assoc_array[$var];

避免在大数组上使用 in_array
避免在大的数组上使用 in_array(), 同时避免在循环中对包含 200 个以上元素的数组使用这个函数. in_array() 会非常消耗资源. 对于小的数组这种影响可能很小, 但是在一个循环中检查大数组可能会需要好几秒钟的时间. 如果您确实需要这个功能, 请使用 isset()来查找数组元素. 实际上是使用键名来查询键值. 调用 isset($array[$var]) 会比 in_array($var, array_keys($array)) 要快得多.
SQL 脚本格式
SQL 代码常常会变得很长, 如果不作一定的格式规范, 将很难读懂. SQL 代码一般按照以下的格式书写, 以关键字换行:

  1. $sql = 'SELECT *
  2. <-one tab->FROM ' . SOME_TABLE . '
  3. <-one tab->WHERE a = 1
  4. <-two tabs->AND (b = 2
  5. <-three tabs->OR b = 3)
  6. <-one tab->ORDER BY b';

这里是应用了制表符后的例子:

  1. $sql = 'SELECT *
  2. FROM ' . SOME_TABLE . '
  3. WHERE a = 1
  4. AND (b = 2
  5. OR b = 3)
  6. ORDER BY b';

禁止使用单字母开头的变量(无意义的变量)

  1. $tKey, $tVal

14. 使用 (int) code 替代 intval(code)

  1. // deprecated
  2. $is_apply = intval(input('is_apply'));
  3. // succcess
  4. $is_apply = (int) input('is_apply');

15. 去除多余的 else

  1. // deprecated
  2. $id = (int) input('id');
  3. if ($id) {
  4. $item = PluginHelp::find($id, ['id', 'help_title as title', 'updated_at', 'content']);
  5. return Resp::web(Resp::SUCCESS, '获取文章内容成功', $item);
  6. }
  7. else {
  8. return Resp::web(Resp::SUCCESS, '列表为空');
  9. }
  10. // suggest
  11. $id = (int) input('id');
  12. if ($id) {
  13. $item = PluginHelp::find($id, ['id', 'help_title as title', 'updated_at', 'content']);
  14. return Resp::web(Resp::SUCCESS, '获取文章内容成功', $item);
  15. }
  16. return Resp::web(Resp::SUCCESS, '列表为空');

16. 对象和数组的不同

  1. // Json 中对象返回 {}
  2. // Json 中数组返回 []
  3. // PHP 中空数组和对象均为 []

17. 使用临时变量以避免复合条件语句

  1. # good
  2. $itemValid = $itemMoney > 800 && $level > 3 && $valid > 0;
  3. if($itemValid && isReady()) {
  4. display();
  5. }
  6. # bad
  7. if($itemMoney > 800 && $level > 3 && $valid > 0 && isReady()) {
  8. display();
  9. }

18. Switches 语句应该套用以下格式,并且每个分支必须注释清楚

  1. switch (condition) {
  2. case 0 :
  3. // show something
  4. break;
  5. default :
  6. // this is some code
  7. break;
  8. }

19. 数字变量转换

  1. // bad
  2. $ids = !is_array($id) ? [$id] : $id;
  3. // good
  4. $ids = (array) $id;

20. 不要使用硬编码

  1. // 写常量是属于硬编码, 这里不要使用硬编码
  2. // Bad
  3. if ($owner->pub_is_good != 1) {
  4. return $this->setError('您并非优质商人, 无法发布优质订单');
  5. }
  6. // Good
  7. if ($owner->pub_is_good != Front::PUB_GOOD) {
  8. return $this->setError('您并非优质商人, 无法发布优质订单');
  9. }
  1. // bad
  2. $db->query("Update xd_company ...");
  3. // good
  4. $db->query("Update {$db_prefix}company ...");

21. 文件命名导致的冲突

  1. // 文件名称
  2. // TransToaccountTransfer.php
  3. // 这里会出现文件类不存在的情况
  4. // Found by Lipengtao
  5. // 类名称
  6. class TransToAccountTransfer {
  7. ...
  8. }

22. 不正确的 Switch 使用

  1. // bad : 目标值和匹配值不同
  2. switch ($win_dot) { // 0
  3. case ($win_dot == 0): // true
  4. $result = $one_number->multiply($coefficient)->getValue();
  5. break;
  6. case ($win_dot >= 1 && $win_dot < 100): // false
  7. $dis_price = $one_number->multiply($this->discount($win_dot))->multiply($coefficient)->getValue();
  8. $result = $one_number->subtract($dis_price)->multiply($coefficient)->getValue();
  9. break;
  10. case ($win_dot > 99):
  11. $result = $up_number->multiply($coefficient)->getValue();
  12. break;
  13. }
  14. // good : 应该使用 if - else
  15. if ($win_dot == 0):
  16. $result = $one_number->multiply($coefficient)->getValue();
  17. elseif ($win_dot >= 1 && $win_dot < 100):
  18. $dis_price = $one_number->multiply($this->discount($win_dot))->multiply($coefficient)->getValue();
  19. $result = $one_number->subtract($dis_price)->multiply($coefficient)->getValue();
  20. else ($win_dot > 99):
  21. $result = $up_number->multiply($coefficient)->getValue();
  22. endif

23. 负数的写法

负数使用 ‘-‘ 来进行拼凑感觉会比较容易出问题

  1. # bad : 这里是减去的总金额
  2. $price = '-' . $order->total_price;
  3. # good : 这里是我认为标准的写法
  4. $price = (new Number($order->total_price))->negate()->getValue();

24. 注意 数组 + 和 array_merge 的不同

两个数组相加 如果前面的数组和后面数组 key 相同,前面的 key 值会覆盖后面的 key 值,array_merge() 后面的数组相同的 key 会覆盖前面的

25. 检测存在数据, 先进行检测, 然后再检测数据的值

  1. // 修复前 : 发放会员折扣券
  2. $setting = sys_setting(DiscountCoupon::settingKey());
  3. if ($setting['week'] && $setting['send_at'] && isset($setting['week'], $setting['send_at'])) {
  4. ......
  5. }
  6. // 修复后, 先检测是否设定, 然后再检测值
  7. $setting = sys_setting(DiscountCoupon::settingKey());
  8. if (isset($setting['week'], $setting['send_at']) && $setting['week'] && $setting['send_at']) {
  9. ......
  10. }

26. 数据库的 clone

  1. // clone
  2. $Db = OrderUserCoupon::where('account_id', $account_id)
  3. ->where('status', OrderUserCoupon::STATUS_UNUSED)
  4. ->where('start_at', '<=', Carbon::now()->toDateString());
  5. if (!(clone $Db)->exists()) {
  6. return $this->setError('暂无可用优惠券');
  7. }

27. 同一个函数中存在多个不同类型的变量采用匈牙利命名法

  1. // 匈牙利命名法
  2. $arrCoupon = $coupon->toArray();
  3. $objCoupon = $coupon;

28. 空数组约束

  1. // 空数组
  2. $array = null;
  3. $array = (array) $array;

29. 注释的写法

需要支持代码提示

  1. /**
  2. * 系统推荐优惠券
  3. * @param array|OrderUserCoupon[] $coupons 可用优惠券列表
  4. * @param float $price 订单价格
  5. * @return array|mixed
  6. */

30. 三元运算符的简写[?:/??]

Using null coalescing operator in PHP 7 simplifies code structure.

  1. // bad
  2. Form::model(isset($data['params']) ? $data['params'] : null)
  3. // good
  4. Form::model($data['params'] ?? null)

下面这种情况使用与 value 已经定义的情况

  1. // bad
  2. $output = $value ? $value : 'No value set.';
  3. // good
  4. $output = $value ?: 'No value set.';