我目前正在阅读PHP规范:https://github.com/php/php-langspec
现在,我看到 list-intrinsic 规范here,其中指出对于 list-intrinsic 构造,如下所示, simple-assignment-expression 的手边必须是指定数组的表达式:
list (list-expression-list opt ) = expression
但是来自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
}
如果没有更多行,PDOStatement::fetch(PDO::FETCH_NUM)
会返回FALSE
。但 assignment-expression 的右侧必须是数组 - 而FALSE
不是数组。所以这会导致致命错误,对吧?
我是否遗漏了规范中的内容,或者这是否真的不一致?
<小时/> According PHP bugreport
答案 0 :(得分:6)
这是故意在php的实现中完成的,以允许这段可疑的代码:
while (list($key, $value) = each($array)) {
// ...
}
each()
的结果可能是false
,否则会引发一个令人讨厌的错误,因此虽然这种行为似乎违反了规范,但它主要是为了保持向后兼容性。
虽然不太可能,但下一版本的PHP将废除此行为是可能的,但此时我建议可以编辑规范以反映这一特定的人工制品,尽管隐含的未定义行为可以用于目的也是:)
可以找到here的代码;目前,右侧表达支持:
ArrayAccess
,在&#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
和$salary
,FALSE
值将终止环。但是,语言规范并未预期或保证此行为。