书写技术成长之路

PHP 常见误区

foreach 循环中的变量引用

foreach中的变量引用可以用来更改数组中的元素,例如

$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
    $value = $value * 2;
} 
// $arr foreach后的值为(2, 4, 6, 8)

但是变量的引用也会导致一些意想不到的bug,比如下面的例子

$array = [1, 2, 3];
foreach ($array as &$value) {} // 通过引用的方式, $value是数组$array元素的引用
echo implode(',', $array), "\n";

foreach ($array as $value) {} // 通过赋值的方式
echo implode(',', $array), "\n";

// 结果是
1,2,3
1,2,2

后面再循环$array的结果却不是1,2,3而是1,2,2 这是因为在每一次循环过后,$array中的元素都会赋给$value, 因为$value是引用的方式,在循环结束后,$value仍然引用数组的最后一个元素,也就是$array[2], 这时候在第二次foreach循环的时候,因为$value仍然是引用$array[2], 当把数组中的每一个元素赋给$value的时候,$array[2]的值也跟着改变,在第二次foreach的时候

  1. 把$array[0]赋值给$value,因为$value是引用$array[2], 所以这个时候$array[2]的值也变为1
  2. 把$array[1]赋值给$value的时候,因为$value是引用$array[2], 所以$array[2]的值变为2
  3. 这个时候需要把$array[2]的值赋给$value, 因为$array[2]=2,所以$value的值也是2 这样,foreach之后,$array的元素就变为[1, 2, 2]了。 所以在foreach修改元素值的时候,为了避免引入bug,就需要删除引用
$arr = array(1, 2, 3);
foreach ($arr as &$value) {
    $value = $value * 2;
}
unset($value);       // 删除$value和$arr中最后一个元素的引用

isset的误区

isset检查变量是否设置的时候并不可靠

$arr = [];
$arr['name'] = null;

var_dump(isset($arr['name'])); // result is false

// 如果要检测变量是否存在并不为空
if ($arr['name']) {
   // key存在并不为空
} else {

}

isset在变量的值是null的时候依然会返回false, 所以如果要检测变量存在并且不为空要使用if来判断,最主要的是取决于你期望获得的结果是什么。

$_POST误区

$_POST超级全局变量并不总是能获得POST方法提交来的数据

$.ajax({
    url: 'http://my.site/some/path',
    method: 'post',
    data: JSON.stringify({a: 'a', b: 'b'}),
    contentType: 'application/json'
});

上面这段通过ajax请求并且请求方法是post,不过它的contentType是application/json,这种方式在当前开发中很常见, 但是打印$_POST输出的却是空数组,这是为什么呢? 这是因为在POST方法请求PHP执行时,PHP只能处理content type是application/x-www-form-urlencode或者multipart/form-data格式的, 所以上面这种application/json Content Type不在$_POST变量中,那么我们该怎么处理这种格式呢

// 通过这种方式来获得content type是`application/json`的数据
$data = json_decode(file_get_contents('php://input'), true);

参考

https://www.toptal.com/php/10-most-common-mistakes-php-programmers-make