get_object_vars根据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

看吗?键是整数或字符串,具体取决于版本。

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

如果您更仔细地查看该3v4.org输出的版本,则在7.0.0中以7.0.0.16和7.1.0和7.1.0的形式打破了它,直到7.1.2。因此,这是一个在7.0中引入的错误,并及时固定在7.0.17和7.1.3(均发布2017年3月16日)上。

查看PHP ChangElog,我们可以看到一个相关的外观条目:

修复错误#73998(array_key_exists在get_object_vars创建的数组中失败)。

这将我们带到错误跟踪器,然后从那里提交DD9CF23457E21D2BDA29DC92D437B9DB9DBD14027B2 th git Repo:

错误#73998:数字属性无法从get_object_vars

访问

修复程序涉及添加检查是否存在数字键,并跳过标有" fast_copy"的块。

因此,这是在PHP 7开发过程中进行性能优化的不希望的副作用,现在已固定在所有受支持的版本中。

有趣的是,安德里亚(Andrea)在错误报告中评论说,它与RFC密切相关以改变对象到阵列铸件的行为,该行为描述了一般问题:

由于数组和对象在它们可以拥有的键上具有不同的限制,而基础上的伸缩类型,Zend Engine必须在Hashtables上方的一层,在代码上实现数组和对象本身的代码中强制执行其限制。这意味着,如果该代码被绕过并且基本的伸展度直接修改,则可以使用无效的内部状态存在数组和对象。

和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"one_answers" 2"产生一个数组。使用get_object_vars()。

时也会发生同一问题

RFC在7.2.0中实现,因为它改变了记录的行为,但是get_object_vars()的行为实际上是7.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返回关联数组。

返回值¶

返回定义对象的可访问的非静态的关联数组 范围中指定对象的属性。如果财产没有 被分配了一个值,将以空值返回。

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

最新更新