php怎么注意细节,细节注意

## 细节注意

一些重要但是容易被忽略的细节记录。不起眼但很重要的知识。

![](http://cdn.aipin100.cn/微信图片_20190316074725.jpg)

家里的电器坏了,90%的原因是因为没有插电源插头。

写代码也是这样,很多时候往往是因为不够细心而出了问题,比如写错变量名、多了空格等,所以出现问题时最应该先细心的检查一遍代码在做调试。

*****

### 判断细节

```php

$a = 0;

if ($a == '') {

echo "output";

}

$b = '0';

if ($b == '') {

echo "not output";

}

```

字符串 `'0'` 和整数 `0` 是不一样的,在开发中要尤其注意这个容易忽略的细节。

----

### 判断尽量使用全等,不要让其自动转换布尔再比较

```php

if (0 == '') {

echo 's'; // output

}

if ('0' == '') {

echo 's'; // no output

}

```

两个类型不同的表达式进行比较时,会先各自自动换成布尔值后在进行比较,**只有当两者类型不一致时才会发生类型自动转换。**

>[tip] 当你要用比较时,永远优先考虑使用全等式。

尽量只让类型确定的表达式参与比较,类型不同时也可以手动转换成一致类型后再全等比较,而不要依赖自动的布尔转换,这样做的原因不仅仅是因为自动转换的性能消耗问题,更重要的是为了避免某些隐蔽的错误发生,使程序更加健壮。

>[tip] 纠正:上面说,类型不同的表达式比较时会自动转换为布尔值,这是不完全正确的,应该为:和布尔值比较时 转换为布尔值,和整形比较时,转换为整形后再比较。

----

### php与js关于判断的区别

```php

if ('string' == 0) {

echo "output";

}

```

js版本:比较上PHP和js是不同的,这有点出乎我的意料

javascript:

```javascript

var a = 'string'; a == 0;

// false

```

*****

### 使用不存在变量报错的细节

使用不存在的变量会报错,但有一种情况例外:

```php

echo $a; // 报错 Notice: Undefined variable: a

$a = null;

echo $a['k']; // 不会报错,值为null

或者

$a = false;

echo $a['k']; // 不会报错,值为null

```

这个细节很重要,因为在严格框架下面,我们总会期望当使用不存在的变量时来抛出异常,如果业务逻辑依赖于此,就得小心了。

*****

#### MYSQL decimal(10,2) 四舍五入问题

```php

# number_format 也会四舍五入

echo number_format(12.088, 2, '.', ''); // 12.09

// 还指望mysql自动保留两位小数,不进行任何四舍五入呢,没想到在 MySQL5.5.53 版本下,会进行四舍五入(12.088 => 12.09),坑啊!看来任何时候都不要指望和依赖外部啊。(目前发现不论什么版本的MySQL 都会直接四舍五舍的)

// 金额格式化(保留两位小数,四舍五舍)

function priceFormat($val)

{

// 保留两位小数不四舍五入

return substr(sprintf("%.3f", $val), 0, -1);

}

```

>[danger] 任何时候都不要指望和依赖外部,所有数据直接算好,交给数据库原原本本的存就可以,不要让数据库参与任何的逻辑部分,以及数据处理。

所以需要自己实现一个,但这也引发一个思考,那就是业务中到底需要保留多少位小数,以及如何对待多余的小数位。最简单粗暴的方式就是 四舍五入 或 四舍五舍,不同交易场景下,这两种方案都有不同的副作用,比如少收或多给。复杂的可能需要考虑银行家算法。

*****

#### 浮点数计算问题

[php浮点数的精度问题深究 - php小松 - CSDN博客](https://blog.csdn.net/a454213722/article/details/52135462)

[PHP浮点数的一个常见问题的解答 | 风雪之隅](http://www.laruence.com/2013/03/26/2884.html)

[关于PHP浮点数你应该知道的(All 'bogus' about the float in PHP) | 风雪之隅](http://www.laruence.com/2011/12/19/2399.html)

[intval遇到小数为什么会减1-CSDN论坛](https://bbs.csdn.net/topics/390789758)

[PHP: BC 数学 函数 - Manual](https://www.php.net/manual/zh/ref.bc.php)

[PHP: GMP 函数 - Manual](https://www.php.net/manual/zh/ref.gmp.php)

```php

// 安全的数字计算方式

// https://www.cnblogs.com/phpfensi/p/8143367.html

// https://www.cnblogs.com/jiqing9006/p/5531687.html

// http://php.net/manual/zh/function.bcdiv.php

// https://blog.csdn.net/LJFPHP/article/details/82255389

// https://www.cnblogs.com/phpper/p/7664069.html

//$m和$n代表传入的两个数值,主要就是这两个数值之间的比较

//$x代表传入的方法,比如是;add,sub等

//$scale 代表传入的小数点位数。这个根据需求更改即可

function calc($m, $n, $x = 'add', $scale = 2)

{

$errors = array(

'被除数不能为零',

'负数没有平方根',

);

switch ($x) {

case 'add':

$t = bcadd($m, $n, $scale);

break;

case 'sub':

$t = bcsub($m, $n, $scale);

break;

case 'mul':

$t = bcmul($m, $n, $scale);

break;

case 'div':

if ($n != 0) {

$t = bcdiv($m, $n, $scale);

} else {

return $errors[0];

}

break;

case 'pow':

$t = bcpow($m, $n, $scale);

break;

case 'mod':

if ($n != 0) {

$t = bcmod($m, $n, $scale);

} else {

return $errors[0];

}

break;

case 'sqrt':

if ($m >= 0) {

$t = bcsqrt($m);

} else {

return $errors[1];

}

break;

}

return $t;

}

```

*****

#### tp $db->find(null) 注意

```php

Db::name('user')->find($userId);

```

如果 `$userId` 是 `null` ,那么 `find(null)` 会查询出来表的第一条数据,由于我们的疏忽,没有 `(int) $userId` ,很可能就造成业务逻辑不符合预期,甚至引起严重而隐秘的BUG。

突然感觉到参数类型严格限制语言的好处了,确实能在很大程度上帮助我们在开发时避免这类错误问题。

*****

### intval() 整形转换问题

> 不管变量前面有多少个0,且数字都小于8,它会当作是八进制数转换成十进制数

[php中intval()函数 - ann_glx - 博客园](https://www.cnblogs.com/anns/p/3494195.html)

*****

#### PHP intval() 处理大整形问题

可以使用:

```php

$paysn = floatval($_POST['paysn']);

```

不能在使用 `intval()`了

[php关于数字防注入,intval溢出,intval - u010412301的博客 - CSDN博客](http://blog.csdn.net/u010412301/article/details/55046733)

[PHP长整型在32位系统中强制转化溢出 - CleverCode的博客 - CSDN博客](http://blog.csdn.net/clevercode/article/details/46423103)

[PHP-php使用intval长度超限的问题? - 德问:编程社交问答](http://www.dewen.net.cn/q/3969)

last update:2018-2-9 10:48:00

*****

### 条件判断优先级问题之括号

```php

// 错误,不符合预期,且不易发现

if (!$info = $db->lock(true)->getRow($sql) || $info['s_patent_claim_status'] != 0) {}

// 正确,符合预期

if (!($info = $db->lock(true)->getRow($sql)) || $info['s_patent_claim_status'] != 0) {}

// 正确,符合预期

if ($patentId && $recordInfo = $db->lock(true)->getRow($sql)) {}

```

所以必须细心谨慎对待这类条件判断问题,越不起眼越往往越容易出错,要确保每个功能上线前都通过完备了测试。

*****

### mysql非严格模式下注意的细节

```

`status` tinyint(4) unsigned NOT NULL DEFAULT 0 COMMENT ''

```

unsigned 无符号的,在非严格模式下, `SET status = -1` 不会更改任何数据,也不会报错,这时就需要注意了。

需要详细的测试,程序要健壮,一定要在严格模式环境下进行开发,对返回进行检查,及时发现问题。

*****

### var_export对标量不友好,特别是浮点型

```php

echo var_export(1.4, true); // 1.3999999999999999

echo var_export('1.4', true); // '1.4'

```

所以如果用到了var_export, 请判断一下是否为标量:

```php

if (!is_scalar($value)) {

$val = var_export($value, true);

} else {

$val = $value;

}

```

*****

### @ 关键字慎用!!!

@ 屏蔽错误显示,页面出错不会往下执行,但是页面不会显示任何报错信息!这让人很无语,如果不是确定的代码,请不要使用@

不然没有错误信息怎么调试呢,错误也很重要,要知道错误、BUG也是程序的一部分,也和程序本身一样的同等重要,没有错误信息、错误处理的程序是不完整的,是没有灵魂的。

----

### 计算时注意数据类型是否为数字

这是js中的情况:

```javascript

1 + '9'

// "19"

```

php也有类似的问题,总之任何时候不要忘记,当你想要计算时,是否严格验证了计算对象的数据类型。

----

### left join 左连一对多问题

a LEFT JOIN b ON a.id = b.mid

a INNER JOIN b ON a.id = b.mid

如果 a只有一条,但是对应的 b有两条,**那么最终结果是两条** ,这点容易让人忽略掉

|id|name|

|---|---|

|10| name |

|id|mid|title|

|---|---|---|

|1|10| title1 |

|2|10| title2 |

>[tip] 如果右表 `ON` 外键字段有重复的,那么就会出现重复数据

~~~

1. select DISTINCT a.id, a.name, b.* from a left join b on a.id = b.mid 重复

2. select DISTINCT a.id, a.name from a left join b on a.id = b.mid 不重复

3. select a.id, a.name from a left join b on a.id = b.mid GROUP BY a.id 不重复

4. select group_concat(DISTINCT a.id) as id,a.name, b.* from a left join b on a.id = b.mid 不重复

https://blog.csdn.net/u010003835/article/details/79154457

DISTINCT 表示对后面的所有参数的拼接取 不重复的记录,相当于 把 SELECT 表达式的项 拼接起来选唯一值。

即:行唯一,所以 上面 1 还是重复,2 不重复

~~~

[https://segmentfault.com/a/1190000017067294](https://segmentfault.com/a/1190000017067294)

[数据库表连接的简单解释 - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2019/01/table-join.html)

[数据库的最简单实现 - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2014/07/database\_implementation.html)

![](http://cdn.aipin100.cn/7ded569002d08f20605acf021f7cb979)

ps: 待研究 on 和 where 的区别,对上面的情况来说理论上 where 写 on 效果也是一样的,甚至提前缩小了范围表连接会更小

on a.id = b.mid where a.id = 1

表关系:条件两边都是表的字段,而不是其它值,如:a.id = b.mid

使用表连接,表关系不可无,并且 on 中只有写 表关系 才有效,如果写了 where 条件 会直接被忽略掉。

需要注意的是,表关系 也可以写在 where 中,但是不建议这样,应该都写在 on 中提前缩小表连接范围。

上面说法错误,正确如下:

1. 左联或右连时 on 都不会缩小主表范围,内联可以缩小范围。

2. on 只是查找副表数据与其连接,副表没有数据不会影响结果(副表字段都是 null)。

3. where 是最终对数据行进行过滤

4. on 上写主表条件没有作用(因为这个条件只是查找副表数据),但可以写副表 条件 缩小 副表范围

5. 如果要过滤最终结果,只能依靠 where

----

### js篇:不要使用 “连相等赋值”

```javascript

function a() {

var b = d = 1;

}

a();

d; // 1

// d 成了全局的了,如果你想将d赋值给b,就不要这样写 “连相等赋值”,而是这样:

function a() {

var d = 1, b = d;

}

a();

```

----

### mysql_insert_id() 受 insert 和update影响

所以 mysql_insert_id 不一定是取到 最后 insert 的id,如果中间 有update,则返回0 。

*****

### 注意隐含产生的引用

```php

$arr = [['a'], ['b']];

var_dump($arr);

foreach ($arr as &$item) {

foreach ($item as &$value) {

}

// unset($value);

}

// unset($item);

var_dump($arr);

```

```

array(2) {

[0]=>

array(1) {

[0]=>

string(1) "a"

}

[1]=>

array(1) {

[0]=>

string(1) "b"

}

}

array(2) {

[0]=>

array(1) {

[0]=>

string(1) "a"

}

[1]=>

&array(1) {

[0]=>

&string(1) "b"

}

}

```

----

last update: 2019-5-28 23:42:01

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值