get_object_vars根据PHP版本返回不同的结果

时间:2017-09-01 12:43:37

标签: php

功能实现有时会在不同版本之间发生变化,这并不奇怪,但不是这样......看看:

$array = ["abc","def"];
$object = new stdclass();
foreach($array as $index => $value) {
    $object->$index = $value;
}
var_dump(get_object_vars($object));

对于5.6.x,然后是我们得到7.0.17和7.1.3:

array(2) { 
[0]=> string(3) "abc" 
[1]=> string(3) "def" 
}

但是对于7.0.0和7.0.16以及7.1.0,我们得到:

array(2) { 
["0"]=> string(3) "abc" 
["1"]=> string(3) "def" 
} 

演示:https://3v4l.org/jog4A

请参阅?键是整数或字符串,具体取决于版本。

为什么呢?这些变化背后的原因是什么?为什么在任何地方都没有记录这个?或者......是吗?

2 个答案:

答案 0 :(得分:1)

如果你仔细观察3v4.org输出上的版本,它在7.0.0中被破坏,包括7.0.16和7.1.0,包括7.1.2。因此,这是7.0中引入的错误,并在7.0.17和7.1.3(均于2017年3月16日发布)中及时修复了两个活动版本。

查看the PHP changelog,我们可以看到相关的相关条目:

  

修正了错误#73998(array_key_exists在get_object_vars创建的数组上失败)。

这会引导我们the bug tracker,从那里到commit dd9cf23457e21d2bda29dc92d437b9dbd14027b2 in th git repo

  

BUG#73998:无法从get_object_vars

访问数字属性

该修复包括添加一个检查是否存在数字键,如果有,则跳过标有“fast_copy”的块。

因此,这是在PHP 7开发过程中进行的性能优化的不良副作用,现在已在所有受支持的版本中得到修复。

有趣的是,Andrea在错误报告中评论说它与描述一般问题的an RFC to change the behaviour of object-to-array casts密切相关:

  

因为数组和对象对底层的HashTable类型有不同的限制,它们可以拥有什么类型的密钥,Zend引擎必须在HashTables之上的层上强制执行它们的限制,在实现数组和对象本身的代码中。这意味着如果绕过该代码并直接修改底层HashTable,则数组和对象可能存在无效的内部状态。

RFC解决的具体案例:

  

例如,$ arr = [0 => 1,1 => 2,2 => 3]; $ obj =(object)$ arr;生成一个名为1和2的不可访问属性的对象,而$ obj = new stdClass; $ obj-> {'0'} = 1; $ obj-> {'1'} = 2; $ obj-> {'2'} = 3;生成一个具有不可访问键“0”,“1”和“2”的数组。使用get_object_vars()时也会出现同样的问题。

RFC在7.2.0中实现,因为它改变了记录的行为,但get_object_vars()的行为实际上是7.0中的无意更改,因此实现为错误修复。

答案 1 :(得分:0)

实际上这是一个错误,因为变量必须以字母开头。

  

变量名遵循与PHP中其他标签相同的规则。一个有效的   变量名以字母或下划线开头,后跟任意名称   字母,数字或下划线的数量。作为正则表达式,   它将被表达为:'[a-zA-Z_ \ x7f- \ xff] [a-zA-Z0-9_ \ x7f- \ xff] *'

http://php.net/manual/en/language.variables.basics.php

因此,当您尝试设置变量$object->$index = $value;时,它必须抛出错误(您无法设置变量,如$1 = 'foo';$obj->1 = 'foo';)。

array(2) { 
["0"]=> string(3) "abc" 
["1"]=> string(3) "def" 
} 

是正确的结果,因为get_object_vars返回关联数组。

  

返回值¶

     

返回定义的对象可访问非静态的关联数组   范围中指定对象的属性。如果房产没有   如果已赋值,则返回NULL值。

http://php.net/manual/en/function.get-object-vars.php