【问题标题】:PHP quirks and pitfalls [closed]PHP的怪癖和陷阱[关闭]
【发布时间】:2009-07-09 17:39:23
【问题描述】:

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

我希望这个问题成为所有想要了解 PHP 的陷阱和例外的人的 wiki,我们可能认为这是规则。但请不要写出一般性的回复,例如:

有些函数接收参数为 $needle$haystack,而有些是 $haystack, $needle.

告诉函数名称。你有一些我的答案作为例子。哦,每个答案添加一个陷阱。这样我们就可以(通过投票)看看哪一个是最被鄙视的。

我不想引发一场激烈的战争,保持主题。如果你想写一些关于 PHP 的不好的东西,那就把它作为对相应答案的评论。

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

更新:

在 Andrew Moore 发表评论后,我认为答案还应该包含针对该陷阱的解决方案或解决方法。

【问题讨论】:

  • 从 php 5.3.3 开始,如果使用命名空间,则不能再使用类名作为构造函数名。您必须使用“__construct”。不会发出警告,但调用“new MyClass”不会执行构造函数中的代码。为一个不错的陷阱万岁。

标签: php


【解决方案1】:

序列化处理 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 对象也是如此。

【讨论】:

    【解决方案2】:

    非行业标准运算符优先级。

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

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

    【讨论】:

    • echo() 接受多个参数的可能性也可以在这里使用:echo 'foo: ', $x+1, 'bar';
    • 值得注意的是,这里有 两个 时髦的东西:不仅优先级不是你想要的,而且 ("foo: 1" + 1) 也不'不要连接;它显然等于 1,而不是 "foo: 11"。
    • @ojrac,那是因为 PHP 中的连接运算符是 . (点),而不是许多其他语言中的 +(加号)。 + 用于算术加法,"foo: 1" 被评估为 0,以便将 1 添加到它,因此最终结果为 1。
    【解决方案3】:

    我讨厌使用?&gt; 结束标记关闭php 文件时会出现问题(这似乎应该是相反的方式)。例如,在 ?> 之后包含一个带有一些空格的文件,然后尝试更改标题(假设没有输出缓冲)。啊。我花了很长时间才学会永远不要用?&gt;关闭php文件

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        进行真值测试的多种方式(not operatorempty()is_null()isset())+ 弱类型 = this

        通过一些纪律,您基本上可以避免参考此表:

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

        • 如果您想测试表单输入的假值(它将“0”视为假),请始终使用empty()

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

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

        【讨论】:

          【解决方案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 中会变得更好,因为它具有理智的行为,但我仍然会时不时地被这个抓住。

          【讨论】:

          • 你知道幕后发生了什么吗?我很好奇为什么 php 会返回这个。
          • =& 赋值使数组中的最后一项成为对 $item 变量的引用。在 foreach 循环的每次迭代中,这意味着 $testarray[3] 更改为 $item 的当前值。由于 $testarray[2] 是“二”,因此在迭代 $testarray[3] 时该值仍然存在,并且它仍然是 $testarray[3] 的最终值
          【解决方案7】:

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

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

          解决方案:让手册始终处于打开状态。

          【讨论】:

          • 顺便说一句,部分原因是他们最初试图用 strstr()strcmp() 之类的函数来模拟 C。
          【解决方案8】:

          有时您喜欢将函数结果直接传递给另一个函数,该函数只接受变量作为输入。

          例如:

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

          …将导致 E_STRICT 错误“仅应通过引用传递变量”。要让它工作,只需在内部(返回)语句周围添加另一对括号:

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

          (如果您使用命名空间和扩展类,则此行仅返回来自调用对象的类名(不包括命名空间),而不是扩展的父类并可能包含此函数。)

          【讨论】:

          • 刚刚遇到这个错误。谢谢你的解决方案。顺便说一句,PHPStorm 不会将附加括号识别为正确的。 PS:这个问题也可以用\ReflectionObjectgetName()的方法解决。
          【解决方案9】:

          函数在不同操作系统上的行为不同,有些函数仅在特定操作系统上可用。

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

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

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

          【讨论】:

          • exec() 家庭是我在这个类别中的最爱。
          【解决方案10】:

          一些新引入的 PHP 功能无法实现,因为无法保证它们会在托管环境中得到默认支持。

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

          == 编辑 ==

          在 PHP >= 5.4 中,速记 echo 语句不再考虑 short_tags 设置,因此它在支持 PHP 5.4 及更高版本的每个托管环境中都可用。

          【讨论】:

          • 我同意短标签应该是默认的。
          • 短标签是邪恶的。它们与 XML 声明混在一起。你不应该使用它...
          • 不合理。 XML 声明是一种极端情况。接下来你要告诉我短标签“难以阅读”和其他一些废话。简而言之,“
          • 还有一点,我的论点是默认情况下应该启用 short_tags。 PHP 使用“=”作为打开标签的不幸事实是无关紧要的。每个标签比旧方法短 9 个字符。此外,“ini_set()”应该允许覆盖此设置。灵活性会很好。
          • 嵌入式 PHP 是生成 XML 的最差技术之一。
          【解决方案11】:

          虽然字符串可以使用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() ...
          

          【讨论】:

          • foreach(str_split($str) AS $char) { echo $char; }
          • 这是因为字符串不是 PHP 中的字符数组。 for 循环之所以起作用,只是因为括号 [] 是用于访问特定字符的语法糖。不幸的是,这也让人觉得字符串可以作为字符数组进行操作,正如您在 foreach 循环中看到的那样,这是不正确的。正如 Andrew 所指出的,如果需要,使用 str_split() 是一种将其分解为实际数组的简单方法。
          • 与原帖无关...
          • 博士。 Hfuhruhurr,很有趣,因为我写了原始帖子和这个答案。
          【解决方案12】:

          我最喜欢的:

          <?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)';
          

          【讨论】:

          • 这也可以在其他脚本语言中显示,而不仅仅是 PHP。它与如何将“x”转换为整数进行比较有关。
          • == 运算符强制数据类型。无论如何,你应该使用 ===。
          • “== 运算符强制数据...”并非总是如此,有时我确实想将 null,0,'' 视为 false,而将所有其他视为 true。
          • @ItayMoav 有时我确实想将 null,0,'' 视为 false,而将所有其他视为 true。 - 为此,您应该使用专用函数 is_null(), empty() 等。使用类型转换比较操作(例如 ==)并不能正确完成操作,请改用 ===。
          • @Starlays :-D 今天我经验丰富了三年...
          【解决方案13】:

          == 编辑 == 这不再适用于 PHP >= 5.5!

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

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

          empty() 需要一个变量,否则会导致错误。

          解决办法:

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

          【讨论】:

          • 更简单:if (!trim($_GET['s'])) { ...
          【解决方案14】:
          $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
          

          【讨论】:

          • 我相信这个例子,虽然在 PHP 社区中很普​​通,但对于来自严格编程语言的人来说,有很大的帮助。他们中的一些人甚至不知道有三等分之类的东西。
          • 是的,我花了一些时间在我的代码中调试这个问题。我知道 == 强制数据类型,但我不知道 ("a string" == 234) 会评估为真!!
          • 抱歉,但事实并非如此。 "a string" == 142 将评估为假。请参阅ch.php.net/manual/en/types.comparisons.php上的松散比较表
          • Philippe 是对的,它是“a string” == 142; /* false / ... "一个字符串" === 142; // ... "142" == 142; // ... "142" === 142; / false */ ... 有没有 ("a string" == 142) 为 true 的 php 版本?
          猜你喜欢
          • 1970-01-01
          • 2010-09-19
          • 1970-01-01
          • 2010-09-14
          • 2012-02-19
          • 2010-11-16
          • 2010-10-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多