PHP怪癖和陷阱

时间:2009-07-09 17:39:23

标签: php

我意识到,虽然我的大部分经验都是编写PHP应用程序,但我发现自己不时会犯“初学者错误”。这是因为PHP是一种非常有机的语言,因此有一些我不知道的特质,怪癖和陷阱。

我希望这个问题能够成为所有想要了解我们可能认为是规则的PHP陷阱和异常的人的维基。但是,请不要写一般的回答,如:

  

某些函数接收参数为   $needle$haystack,而有些则为   $haystack$needle

告诉功能名称。作为例子,你有几个答案。哦,每个答案添加一个陷阱。通过这种方式,我们可以看到哪些是最受鄙视的(通过投票)。

我不想开始一场火焰战,把它留给主题。如果您想写一些关于PHP的坏事,那么请将其作为对相应答案的评论。

希望这个wiki对我们所有人,初学者和专家都有帮助。

更新

在Andrew Moore的评论之后,我认为答案也应包含解决方案或解决方法。

14 个答案:

答案 0 :(得分:10)

序列化处理XML结构然后反序列化它们的对象不会恢复原始XML结构:

$dom = new DOMDocument;
$dom->loadXML('<test/>');

$dom = serialize($dom);
$dom = unserialize($dom);

var_dump($dom->saveXML());
// $ Warning: DOMDocument::saveXML(): Couldn't fetch DOMDocument in ...
// $ NULL

类似于SimpleXML对象。

答案 1 :(得分:9)

如果您使用?>结束标记关闭php文件(看起来应该是另一种方式),我讨厌如何解决问题。例如,在?&gt;之后包含一些带有空格的文件。然后尝试更改标题(假设没有输出缓冲)。啊。让我学会永远不要用?>

关闭php文件

答案 2 :(得分:8)

非行业标准的运营商优先权。

$x = 1;
echo 'foo: ' . $x+1 . ' bar';

将输出:“1 bar”,而不是预期的“foo: 2 bar”。解决方案:使用括号。

答案 3 :(得分:7)

整数大小取决于平台。在没有任何外部模块的情况下,通常不能在32位机器上使用64位整数。此外,您不能声明无符号整数。

答案 4 :(得分:7)

多种方式进行真相测试(not operatorempty()is_null()isset())+弱打字= this

有了一些纪律,你几乎可以避免引用这个表:

  • 对于一般真值测试,您可以使用布尔比较if ($) {...} if (!$x) { ... }。它的行为与大多数语言中的布尔运算符相同。

  • 如果要测试表格输入是否为虚假值(它将“0”视为假),请始终使用empty()

  • 如果要确定是否设置了变量,请始终使用isset()

  • 如果您只需要检查NULL,请使用is_null()$x === NULL

答案 5 :(得分:6)

我有各种各样的麻烦,将foreach与参考文献相结合

$testarray = array(1 => "one", 2 => "two");
$item = "three";
$testarray[3] =& $item;
foreach ($testarray as $key => $item) {
  // do nothing
}
echo $testarray[3]; // outputs "two"

在PHP4时代,这真的让我失望了,虽然如果你不使用显式引用,但在PHP5中通过明智的行为变得更好,我仍然设法偶尔被这个引起。

答案 6 :(得分:4)

内置函数的命名约定不一致。例如,这组字符串处理函数:

 str_shuffle()
 str_split()
 str_word_count()
 strcasecmp()
 strchr()
 strcmp()

解决方案:始终保持手动打开状态。

答案 7 :(得分:3)

有时你想直接将函数结果传递给另一个函数,它只接受变量作为输入。

例如:

array_pop(  explode('\\', get_class($this))  )

...将导致E_STRICT错误“只应通过引用传递”。要使其正常工作,只需在内部(返回)语句周围添加另一对括号:

array_pop( (explode('\\', get_class($this))) )

(如果您正在使用名称空间和扩展类,则此行仅返回来自调用对象的类名(不带名称空间) - 而不是已扩展的父类,并且可以保留此函数。)

答案 8 :(得分:2)

一些新引入的PHP功能因为无法保证在托管环境中默认支持这些功能。

我最大的烦恼是short_tags设置,它启用了<? foobar(); ?> <?=$var ?> 标记语法。我认为PHP应该默认启用此功能,而不是选择加入。

==编辑==

在PHP&gt; = 5.4中,简写echo语句不再考虑short_tags设置,因此它将在支持PHP 5.4及更高版本的每个托管环境中可用。

答案 9 :(得分:2)

函数在不同的OS上表现不同,某些函数仅在特定的OS上可用。

例如,Windows上的mail()函数无法在$to参数中使用发件人名称。它只能包含电子邮件地址。在Linux上一切正常。

另一个例子,函数strptime()仅在Linux上可用,而不是Windows(这使我进入了我希望在Windows机器上运行的现有项目)。

当然,有些功能只对某些操作系统(如Win32API功能)有意义,但许多其他功能似乎在所有操作系统上应该表现相同,而实际上并非如此。

答案 10 :(得分:1)

尽管可以使用for循环和索引迭代字符串,但不能使用foreach循环对它们进行迭代。例如:

$str = 'foo';
$max = strlen($str);

for ($i=0; $i<$max; $i++)  {
    echo $str[$i];
}
// outputs: foo

foreach ($str as $char) {
    echo $char;
}
// Warning: Invalid argument supplied for foreach() ...

答案 11 :(得分:1)

我的最爱:

<?php
$a = 0;
$b = 'x';
var_dump(FALSE == $a);
var_dump($a == $b);
var_dump($b == TRUE);

echo' <br />Conclusion: TRUE equals FALSE (at least in PHP)';

答案 12 :(得分:1)

==编辑== 这不再适用于PHP&gt; = 5.5!

  

使用Fatal error: Can't use function return value in write context时,我有时会遇到empty()错误   构造。例如:

if (!empty(trim($_GET['s']))) {
    // ...
}
     

empty()需要一个变量,其他任何内容都会导致错误。

     

解决方案:

$s = trim($_GET['s']);
if (!empty($s)) {
    // ...
}

答案 13 :(得分:0)

$x = "a string";

if ($x == 142)
{
    echo "lol, of course $x is a number";
}
else
{
    echo "$x is clearly not equal to 142";
}

运行时:

lol, of course a string is a number

您必须使用 ===

$x = "a string";

if ($x === 142)
{
    echo "lol, of course $x is a number";
}
else
{
    echo "$x is clearly not equal to 142";
}

运行时:

a string is clearly not equal to 142