PHP文档不一致?

时间:2015-02-05 12:23:05

标签: php mysql list pdo specifications

我目前正在阅读PHP规范:https://github.com/php/php-langspec

  1. 现在,我看到 list-intrinsic 规范here,其中指出对于 list-intrinsic 构造,如下所示, simple-assignment-expression 的手边必须是指定数组的表达式

      

    list (list-expression-list opt = expression

  2. 但是来自php.net here list 的文档,给出了一个包含这个的例子:

    $result = $pdo->query("SELECT id, name, salary FROM employees");
    while (list($id, $name, $salary) = $result->fetch(PDO::FETCH_NUM)) {
        //output $id, $name and $salary
    }
    
  3. 如果没有更多行,PDOStatement::fetch(PDO::FETCH_NUM)会返回FALSE。但 assignment-expression 的右侧必须是数组 - 而FALSE不是数组。所以这会导致致命错误,对吧?

    我是否遗漏了规范中的内容,或者这是否真的不一致?

    <小时/> According PHP bugreport

2 个答案:

答案 0 :(得分:6)

这是故意在php的实现中完成的,以允许这段可疑的代码:

while (list($key, $value) = each($array)) {
  // ...
}

each()的结果可能是false,否则会引发一个令人讨厌的错误,因此虽然这种行为似乎违反了规范,但它主要是为了保持向后兼容性。

虽然不太可能,但下一版本的PHP将废除此行为是可能的,但此时我建议可以编辑规范以反映这一特定的人工制品,尽管隐含的未定义行为可以用于目的也是:)

令人讨厌的细节

可以找到here的代码;目前,右侧表达支持:

  1. 数组,
  2. 实现ArrayAccess
  3. 的对象
  4. 别的。
  5. 在&#34;其他的情况下&#34;它只会将null分配给所有列表变量。

    更新

    Nikita Popov已提出以下规范更新作为pull request的一部分:

      

    list-intrinsic必须用作simple-assignment-expression中的左操作数,其右侧操作数必须是指定实现ArrayAccess接口的数组或对象的表达式(称为源数组)。

    ...

      

    此内在函数将源数组的一个或多个元素分配给目标变量。成功时,它返回源数组的副本。如果源数组不是数组或实现ArrayAccess的对象,则不执行任何赋值,返回值为NULL。

    (强调变更)

答案 1 :(得分:1)

The documentation说明以下内容,其中&#34; list-intrinsic&#34;是包含list(...)可能具有的所有有效表单的语法。

  

list-intrinsic必须用作simple-assignment-expression中的左操作数,其右边操作数必须是指定数组的表达式(称为源数组)。

什么是阵列? The documentation说:

  

数组是包含零个或多个元素的集合的数据结构。数组的元素不需要具有相同的类型,并且数组元素的类型可以在其生命周期内改变。

我认为你认为FALSE一个布尔值不符合指定数组的任何东西是正确的,因为它不是一个集合。

&#39;什么必须&#39;意味着在这种背景下?如果我们阅读文档的Conformance部分,我们会发现:

  

在本说明书中,&#34;必须&#34;应被解释为对实施或计划的要求;相反,&#34;不得&#34;被解释为禁止。

     

如果&#34;必须&#34;或&#34;不得&#34;违反约束之外出现的要求,行为未定义。在本说明书中,未定义的行为在单词&#34; undefined behavior&#34;或遗漏任何明确的行为定义。这三者之间的重点没有区别;他们都描述了未定义的行为&#34;。

你认为必须提出致命错误是否正确?我认为你这样做是不正确的。除非在&#34;语义和#34;会发生致命的错误,缺乏行为规范,或者必须要出现这种情况。在约束下意味着没有定义该部分语言的行为。它可以工作。它可以抛出一个错误,一个致命的错误。它可以创建一个人工智能,可以摧毁我们所有人,将月亮变成紫色,或炸毁服务器。这是未定义的。


那发生了什么?文档在语义上说如下:

  

此内在函数将源数组的零个或多个元素分配给目标变量。成功时,它返回源数组的副本。如果源数组实际上是NULL值,则认为是失败,并且列表中的返回值是未定义的。

     

源数组中具有string类型键的所有元素都将被忽略。具有0键的int键的元素被分配给第一目标变量,具有1的int键的元素被分配给第二目标变量,依此类推,直到已经分配了所有目标变量。忽略任何其他数组元素。如果具有int键的源数组元素少于目标变量,则未分配的目标变量将设置为NULL并产生非致命错误。

测试给出以下结果:

$a = 1;
$z = FALSE;
$e = (list( $a, $b ) = $z);

var_dump($a); //NULL
var_dump($b); //NULL
var_dump($z); //FALSE

var_dump($e); //FALSE

事实上,$z = $e似乎只有$z,即使是$z = NULL。除非源数组的长度小于list-intrensic表达式中的变量数量,否则不会为我测试的任何值生成通知,警告或错误。在这种情况下,会显示Notice: Undefined offset

似乎任何非迭代表达式都被视为NULL值(但这是未定义的行为);在我的PHP版本中,似乎任何NULL值都会中途分配;它不会被迭代,但会执行为所有变量赋值NULL的初步部分。

表达式while (list($id, $name, $salary) = $result->fetch(PDO::FETCH_NUM))因此会将NULL分配给$id$name$salaryFALSE值将终止环。但是,语言规范并未预期或保证此行为。