PHP:在5.4版中,使用构造的数组或func_get_args()调用反射方法之间的差异令人困惑
在PHP 5.4中,这是一个非常边缘的例子,关于通过引用传递对象,其中出现以下错误:PHP:在5.4版中,使用构造的数组或func_get_args()调用反射方法之间的差异令人困惑,php,Php,在PHP 5.4中,这是一个非常边缘的例子,关于通过引用传递对象,其中出现以下错误: PHP Warning: Parameter 1 to A::foo() expected to be a reference, value given 但仅作为以下因素的复合效应: 使用反射将继承的方法设置为“可访问” 该方法采用显式引用参数(&argument sig) 然后使用func_get_args()调用它,而不是手动构造args数组 不知道为什么这些事情都会导致这种行为,或者它们是否应该引
PHP Warning: Parameter 1 to A::foo() expected to be a reference, value given
但仅作为以下因素的复合效应:
- 使用反射将继承的方法设置为“可访问”
- 该方法采用显式引用参数(&argument sig)
- 然后使用func_get_args()调用它,而不是手动构造args数组
注释这一行
注释这一行,代码运行正常(例如,对象被正确地传递到'foo'函数):
A类{
私有函数foo(&$arg1){
变量转储('arg1:',$arg1);
}
}
B类扩展了A类{
公共功能条(){
$x=新的stdClass();
$x->baz=‘只是一个值’;
$this->callPrivate($x);
}
私有函数callPrivate($x)
{
$method=new\ReflectionMethod(
“A”,
“福”
);
//*出于某种原因,需要将私有函数更改为“可访问”,以便在5.4中使用
$method->setAccessible(true);
//工作5.4(*见上文),但不在5.5中
$arguments=func_get_args();
//两个都不工作
$arguments=array($x);//invokeArgs($this,$arguments);
}
}
$y=新的B();
$y->bar();
我不明白为什么这两个$arguments数组之间会有任何区别,因为var_转储它们显示相同的输出。因此,我假设这与较低级别的对象“指针”不同有关(超出了我的深度)
另一个问题是,这是否是PHP5.4、5.5或两者中的错误?PHP5.5.6之前的
func_get_args()
从VM堆栈中获取参数,复制它们,并在数组中返回它们。在PHP5.5.6中,引入了一种优化,在常见情况下避免了这些昂贵的副本。不复制zvals,只增加refcount(尽管增加了ref args)
通常,这样的更改对用户代码没有任何影响。但在引擎中有几个地方,可观察到的行为根据zval的参考计数不同。其中一个地方通过引用传递:
对于动态函数调用,如果zval是引用或其refcount==1,则可以通过引用传递zval
在PHP5.5.6之前,func\u get\u args()
返回的数组中的zvals始终具有refcount==1,因此它们根据第二种情况执行。从PHP5.5.6开始,这不再是真的,因为按值zvals将始终具有refcount>1,如果您尝试通过引用传递它们,则会导致错误
注意:在PHP5.5.6之前,该代码实际上不起作用(ByRef被忽略)。这只是一个不幸的巧合,你没有在告诉你时出错;)
更新:由于BC中断,我们决定恢复5.5分支上的更改。您将在PHP 5.5.8中获得旧的行为,而新的行为将只在PHP 5.6中出现。请在此处发布代码,而不是在第三方网站上发布。此外,如果您可以在此处引用预期输出和实际输出,而不必强迫我们自己执行代码,这将有助于澄清您的问题。Fair point@deceze,更新。我希望我能说我完全理解它,但我知道它足以确保这回答了我的问题。回答得很好,谢谢。
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();