posts - 22,  comments - 290,  trackbacks - 0

这篇文件我将继续PHP之旅,并对网上找到的一些PHP中常见的错误进行收集和总结,希望对大家有所帮助。

1. 小错误也能酿大祸

你碰到过仅仅因为一个小小的分号而导致程序出现大问题的情况么?在PHP中如果你while循环的条件后面加上了分号的时候会导致PHP陷入死循环,而且这种错误设置都不会被PHP异常处理系统捕获。我们先看看代码吧:

$i = 0;
while($i < 20); {
//some code here
$i++;
}
echo $i;

这段代码不会导致系统报告错误,然而却会导致系统进入死循环并且最终因为无法及时响应而返回执行超时的错误。

不过在C#中同样的会在编译时就被编译器捕获,并且编译器会知道这是个空循环的错误。当然如果用户一定犯傻写出另外的死循环编译器就没办法了,如:

int i = 0;
while (i < 20) ;

这种情况编译器不会报错。

2. 忘了在break或continue后面加上分号。

同样是小小的符号导致巨大的差异,看下面的代码先:

for($i = 0; $i < 10; $i++) {
for($j = 0; $j < 10; $j++) {
if($i == 0)
break
print $j;
}
}

这段代码最终只会输出0的结果,然后退出循环,然而我们的意愿原本是输出除0外的其他数字。当然如果我们使用规范的方式(如在if条件判断之后加大括号)这个错误很容易避免。

3.单引号还是双引号?

这条严格以上说不能算错误,首先看下面的两行代码:

echo ‘it\’s ok’;
echo “it’s not”;

 

PHP不像C#,单引号和双引号都可以用来表示字符串,因此很多PHP新手往往分不清什么时候该用哪种符号来包裹字符串,或者干脆想用什么就用什么符号。不过单引号和双引号在PHP中是有使用技巧的。如果一个字符串由双引号开始,那么只有双引号被分析器解析。这样,你就可以在双引号串中包含任何其他字符,甚至单引号和PHP变量。e.g.

$var1=’Sean Zhu’;
echo ‘Hello, $var1. I’m Mike!’;//输出:Hello, $var1. I’m Mike!
echo “Hello, $var1. I’m Mike!”;//输出:Hello, Sean Zhu. I’m Mike!

然而正所谓能力越大,消耗越大,双引号拥有复杂的功能也意味着编译器处理它也要花费更多的时间,因此如果我们仅仅想输出简单的字符串的话,最好还是使用单引号。

4. 对浮点数进行比较

作为一个.NET程序员,如果看到下面的代码,你知道它的结果么?

<?php
$a=0.1+0.2;
$b=0.3;
if($a==$b){
echo 'a equals b';
}
else{
echo 'a dosen\'t equal b';
}
?>

在.NET中我们可以毫无犹豫的知道它输出的是a=b的答案,然而这里是PHP的世界,所以永远不要相信浮点数结果精确到了最后一位,也永远不要比较两个浮点数是否相等。

5. 只要method_exists()返回结果为true我们就能调用该它么?

PHP不像C#, 由于C#是一门静态语言,所以我们可以放心大胆的调用任何方法(只要编译器说没问题),然而在php中只要你没执行到最终的方法那一步,一切都还是未知数。因此我们有时候在调用方法之前需要做些额外的检查工作,method_exist()就是其中之一,然而如果方法是protected或者private,该方法同样也会返回true。

6. 使用未初始化的数组

看看下面的代码有什么问题?

<?php
foreach($items as $item) {
$itemIds[] = $item->getId();
}
?>

.NET程序员是永远不会犯上面的错误的,因为编译器会帮我们做检查,然而作为一个PHP程序员,我们始终都要记得给数组初始化:$itemIds = Array(); 可能你会说,上面的代码不初始化也不会有什么问题啊。是的,在正常情况下,只要$items数组里面的元素大于1的时候,这段代码确实没什么问题,然而,如果$items对象为空或者里面元素数量为0,这段代码就有问题了。

7. include(“pages/” . $_GET["pg1"]);

.NET程序员虽然也会遇到各种各样的注入攻击,但至少这个攻击他们不会遇到。实际上,不仅仅是$_GET()参数我们应该检查,其他的如$_POST和$_REQUEST同样具有非常高的危险性。如果始终对用户信任的话,你可能会在不知不觉中加载了别人的代码却浑然不知。

8. 给数组索引添加引号
echo $array[my_key]; //一般能正常工作,但不应该使用
echo $array['my_key']; //正确的方式

PHP编译器会认为没有引号的字符串是一个已经定义的常量,然后它会去符号表中查找这个常量,只有找不到的时候,它才会把这个键值转换为真正的字符串,这就是上面代码为什么也能工作的原因

9. strpos / stripos 函数使用不当。

这个函数在.NET中也有类似的:string.IndexOf(),但在.NET中我们一般不会犯这个初级错误,我们来看看下面的代码有什么问题吧。

if (strpos(‘Spring Brother is cool, isn’t it?, ‘Spring Brother’)) {
echo “Spring Brother is cool”;
}
else {
echo “Spring Brother is NOT cool”;
}

猜猜输出结果是什么?对的,它会输出"Spring Brother is NOT cool”, 因为就像.NET中一样,由于索引从0开始,strpos返回的是0,0会转换为false。而在.net中,如果程序员不进行强制转换,这种错误很容易显现出来。

解决这种初级错误的方式也很简单,常用方式有以下两种:

if (strpos(‘Spring Brother is cool, isn’t it?, ‘Spring Brother) !== false) {
//或者
if (strpos(‘Spring Brother is cool, isn’t it?, ‘Spring Brother’)>= 0 ) {

10. 使用==比较类型。

这种错误其实跟js中的比较一样,由于PHP和js都是弱类型的语言,因此有时我们比较两个对象时可能遇到意想不到的事情。看下面的代码:

$a = 1;
$b =1′;
$c = 1;
$a == $b // true
$a === $b // false
$a === $c // true

我们可以看到,即使$a和$b本来不是同一个对象,但这里==比较返回的结果却是true,因此如果想要对对象做更严格的类型比较时最好用===和!==比较符。

11. empty()方法和魔术方法__get一起使用。

魔术方法很好用,不过当它和empty方法一起使用的时候我们需要格外小心,先上代码:

代码
class Example {
public function __get($name) {
return 'this should not show up as empty';
}
}
function t7(){
$e = new Example();
if(empty($e->something))
echo 'something条件为真';

$var = $e->something;
if(empty($var))
echo '$var条件为真';
}
t7();

我们会发现第一个条件为真,然而同样的值在第二个条件中却为假了。

12. 未对Session中的敏感数据进行任何保护

一个常见的PHP安全错误就是未对存放在Session中的敏感数据进行任何类型的加密处理。在某种程度上这就相当于把用户的密码等信息裸露在网络当中,某些黑客可以通过Sesion伪造等技术来窃取用户的密码信息。

posted on 2010-03-07 15:21 jujusharp 阅读(...) 评论(...) 编辑 收藏