浅析PHP编程中10个最常见的错误

PHP是个伟大的web开发语言,灵活的语言,但是看到php程序员周而复始的犯的一些错误。我做了下面这个列表,列出了PHP程序员经常犯的10中错误,大多数和安全相关。看看你犯了几种www.123uq.com
目前学习PHP很多朋友,在平时的日常程序开发工程中总会遇到各种各样的问题,本篇经验将为大家介绍PHP开发中10个最常见的问题,希望能够对朋友有所帮助。

www.888eq.com


错误1:foreach循环后留下悬挂指针


  在foreach循环中,如果我们需要更改迭代的元素或是为了提高效率,运用引用是一个好办法:www.123ul.com


$arr = array(1, 2, 3, 4); 
foreach ($arr as &$value) { 
 $value = $value * 2; 

// $arr is now array(2, 4, 6, 8)
  这里有个问题很多人会迷糊。循环结束后,value并未销毁,value其实是数组中最后一个元素的引用,这样在后续对$value的使用中,如果不知道这一点,会引发一些莫名奇妙的错误:)看看下面这段代码:


$array = [1, 2, 3]; 
echo implode(',', $array), "\n"; 
 
foreach ($array as &$value) {}  // by reference 
echo implode(',', $array), "\n"; 
 
foreach ($array as $value) {}   // by value (i.e., copy) 
echo implode(',', $array), "\n";
  上面代码的运行结果如下:


1,2,3 
1,2,3 
1,2,2
  你猜对了吗?为什么是这个结果呢?


  我们来分析下。第一个循环过后,$value是数组中最后一个元素的引用。第二个循环开始:


第一步:复制arr[0]到value(注意此时value是arr[2]的引用),这时数组变成[1,2,1]
第二步:复制arr[1]到value,这时数组变成[1,2,2]
第三步:复制arr[2]到value,这时数组变成[1,2,2]
  综上,最终结果就是1,2,2


  避免这种错误最好的办法就是在循环后立即用unset函数销毁变量:


$arr = array(1, 2, 3, 4); 
foreach ($arr as &$value) { 
  $value = $value * 2; 

unset($value);  // $value no longer references $arr[3]
 错误2:对isset()函数行为的错误理解


  对于isset()函数,变量不存在时会返回false,变量值为null时也会返回false。这种行为很容易把人弄迷糊。。。看下面的代码:


$data = fetchRecordFromStorage($storage, $identifier); 
if (!isset($data['keyShouldBeSet']) { 
  // do something here if 'keyShouldBeSet' is not set 
}
  写这段代码的人本意可能是如果data[′keyShouldBeSet′]未设置,则执行对应逻辑。但问题在于即使data['keyShouldBeSet']已设置,但设置的值为null,还是会执行对应的逻辑,这就不符合代码的本意了。


  下面是另外一个例子:


if ($_POST['active']) { 
  $postData = extractSomething($_POST); 

 
// ... 
 
if (!isset($postData)) { 
  echo 'post not active'; 
}
  上面的代码假设POST[′active′]为真,那么postData应该被设置,因此isset(postData)会返回true。反之,上面代码假设isset(postData)返回false的唯一途径就是$_POST['active']也返回false。


  真是这样吗?当然不是!


  即使POST[′active′]返回true,postData也有可能被设置为null,这时isset($postData)就会返回false。这就不符合代码的本意了。


  如果上面代码的本意仅是检测$_POST['active']是否为真,下面这样实现会更好:


if ($_POST['active']) { 
  $postData = extractSomething($_POST); 

 
// ... 
 
if ($_POST['active']) { 
  echo 'post not active'; 
}
  判断一个变量是否真正被设置(区分未设置和设置值为null),array_key_exists()函数或许更好。重构上面的第一个例子,如下:


$data = fetchRecordFromStorage($storage, $identifier); 
if (! array_key_exists('keyShouldBeSet', $data)) { 
  // do this if 'keyShouldBeSet' isn't set 
}
  另外,结合get_defined_vars()函数,我们可以更加可靠的检测变量在当前作用域内是否被设置:


if (array_key_exists('varShouldBeSet', get_defined_vars())) { 
  // variable $varShouldBeSet exists in current scope 
}
 错误3:混淆返回值和返回引用


  考虑下面的代码:


class Config 

  private $values = []; 
 
  public function getValues() { 
    return $this->values; 
  } 

 
$config = new Config(); 
 
$config->getValues()['test'] = 'test'; 
echo $config->getValues()['test'];
  运行上面的代码,将会输出下面的内容:


PHP Notice: Undefined index: test in /path/to/my/script.php on line 21
  问题出在哪呢?问题就在于上面的代码混淆了返回值和返回引用。在PHP中,除非你显示的指定返回引用,否则对于数组PHP是值返回,也就是数组的拷贝。因此上面代码对返回数组赋值,实际是对拷贝数组进行赋值,非原数组赋值。


// getValues() returns a COPY of the $values array, so this adds a 'test' element 
// to a COPY of the $values array, but not to the $values array itself. 
$config->getValues()['test'] = 'test'; 
 
// getValues() again returns ANOTHER COPY of the $values array, and THIS copy doesn't 
// contain a 'test' element (which is why we get the "undefined index" message). 
echo $config->getValues()['test'];
  下面是一种可能的解决办法,输出拷贝的数组,而不是原数组:


$vals = $config->getValues(); 
$vals['test'] = 'test'; 
echo $vals['test'];
  如果你就是想要改变原数组,也就是要反回数组引用,那应该如何处理呢?办法就是显示指定返回引用即可:


class Config 

  private $values = []; 
 
  // return a REFERENCE to the actual $values array 
  public function &getValues() { 
    return $this->values; 
  } 

 
$config = new Config(); 
 
$config->getValues()['test'] = 'test'; 
echo $config->getValues()['test'];
  经过改造后,上面代码将会像你期望那样会输出test。


  我们再来看一个例子会让你更迷糊的例子:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值