PHP:混淆使用构造数组的反射方法或版本5.4中的func_get_args()之间的差异

Sam*_*ams 11 php

这是PHP 5.4中关于通过引用传递对象的一个​​非常优秀的案例,其中获取此错误:

PHP Warning:  Parameter 1 to A::foo() expected to be a reference, value given
Run Code Online (Sandbox Code Playgroud)

但仅作为复合效应:

  • 使用反射将继承的方法设置为"可访问",
  • 并且该方法采用显式引用参数(&argument sig)
  • 然后使用func_get_args()调用它,而不是手动构造args数组.

不知道为什么这些东西都会导致这种行为或是否应该.

需要注意的是,PHP 5.5中不存在此效果.

这是导致上述错误的代码,但是如果你COMMENT THIS LINE对代码运行正常注释(例如,对象被正确传递给'foo'函数):

class A {
    private function foo(&$arg1) {
        var_dump('arg1: ', $arg1);
    }   
}

class B extends A {
    public function bar() {
        $x = new stdClass();
        $x->baz = 'just a value';
        $this->callPrivate($x);
    }

    private function callPrivate($x)
    {
        $method = new \ReflectionMethod(
            'A',
            'foo'
        );

        //* for some reason, the private function needs to have been changed to be 'accessible' for this to work in 5.4
        $method->setAccessible(true);

        //working 5.4 (* see above) but not in 5.5
        $arguments = func_get_args();

        //not working in either
        $arguments = array($x); // <---- COMMENT THIS LINE TO SEE IT WORK IN PHP 5.4

        return $method->invokeArgs($this, $arguments);
    }
}

$y = new B();
$y->bar();
Run Code Online (Sandbox Code Playgroud)

我不明白为什么两个$ arguments数组之间会有任何区别,因为var_dumping它们显示相同的输出.因此,我认为这与较低级别的对象'指针'不同(我的深度在这里)?

另一个问题是,如果这是PHP 5.4,5.5或两者中的错误?

Nik*_*kiC 4

在 PHP 5.5.6 之前,func_get_args()从 VM 堆栈获取参数,复制它们并在数组中返回它们。PHP 5.5.6 中引入了一项优化,可以避免常见情况下这些昂贵的副本。不是复制 zval,而是仅增加引用计数(尽管有 by-ref args)。

通常这样的更改对用户代码的影响为零。但在引擎中的一些地方,可观察到的行为会根据 zval 的引用计数而有所不同。其中一个地方是按引用传递:

对于动态函数调用的情况,如果 zval 是引用或者具有 refcount==1 ,则可以通过引用传递 zval 。

在 PHP 5.5.6 之前,返回的数组中的 zvalfunc_get_args()始终具有 refcount==1,因此它们基于第二种情况进行处理。从 PHP 5.5.6 开始,这不再是正确的,因为按值 zval 的 refcount 总是>1,如果您尝试按引用传递它们,则会导致错误。

注意:该代码在 PHP 5.5.6 之前实际上不起作用(by-ref 被忽略)。这只是一个不幸的巧合,你没有收到错误提示;)

更新:由于 BC 中断,我们决定恢复 5.5 分支上的更改。您将在 PHP 5.5.8 中恢复旧行为,而新行为仅在 PHP 5.6 中出现。