Dan*_*ugg 8 php pass-by-reference magic-methods dynamic-function
我一直在阅读SO和其他地方,但我似乎无法找到任何结论.
有没有办法通过此调用堆栈有效地携带引用,从而产生所需的功能,如下面的示例所述?虽然该示例并未尝试解决此问题,但它确实说明了问题:
class TestClass{
// surely __call would result similarly
public static function __callStatic($function, $arguments){
return call_user_func_array($function, $arguments);
}
}
// note argument by reference
function testFunction(&$arg){
$arg .= 'bar';
}
$test = 'foo';
TestClass::testFunction($test);
// expecting: 'foobar'
// getting: 'foo' and a warning about the reference
echo $test;
Run Code Online (Sandbox Code Playgroud)
只关注call_user_func_array(),我们可以确定(至少在PHP 5.3.1中)你不能通过引用隐式传递参数:
function testFunction(&$arg){
$arg .= 'bar';
}
$test = 'foo';
call_user_func_array('testFunction', array($test));
var_dump($test);
// string(3) "foo" and a warning about the non-reference parameter
Run Code Online (Sandbox Code Playgroud)
通过显式传递数组元素$test作为参考,我们可以缓解这个问题:
call_user_func_array('testFunction', array(&$test));
var_dump($test);
// string(6) "foobar"
Run Code Online (Sandbox Code Playgroud)
当我们引入类时__callStatic(),引用的显式调用时参数似乎按照我的预期进行,但是发布了弃用警告(在我的IDE中):
class TestClass{
public static function __callStatic($function, $arguments){
return call_user_func_array($function, $arguments);
}
}
function testFunction(&$arg){
$arg .= 'bar';
}
$test = 'foo';
TestClass::testFunction(&$test);
var_dump($test);
// string(6) "foobar"
Run Code Online (Sandbox Code Playgroud)
省略参考运算符TestClass::testFunction()导致$test通过值传递__callStatic(),当然通过值作为数组元素传递给testFunction()via call_user_func_array().这会产生警告,因为testFunction()需要参考.
黑客攻击,一些额外的细节浮出水面.__callStatic()如果写入以引用(public static function &__callStatic())返回的定义没有可见效果.此外,$arguments在__callStatic()作为引用重新构建数组元素时,我们可以看到它的call_user_func_array()工作方式与预期的一样:
class TestClass{
public static function __callStatic($function, $arguments){
foreach($arguments as &$arg){}
call_user_func_array($function, $arguments);
var_dump($arguments);
// array(1) {
// [0]=>
// &string(6) "foobar"
// }
}
}
function testFunction(&$arg){
$arg .= 'bar';
}
$test = 'foo';
TestClass::testFunction($test);
var_dump($test);
// string(3) "foo"
Run Code Online (Sandbox Code Playgroud)
这些结果是预期的,因为$test不再通过引用传递,更改不会传回其范围.然而,这证实call_user_func_array()了事实上正在按预期工作,并且问题肯定局限于调用魔法.
在进一步阅读时,似乎它可能是PHP处理用户函数和__call()/ __callStatic()magic 的"错误" .我已经仔细阅读了错误数据库中的现有问题或相关问题,并找到了一个,但无法再次找到它.我正在考虑发布另一份报告,或要求重新开放现有报告.
这是一件有趣的事。
TestClass::testFunction(&$string);
Run Code Online (Sandbox Code Playgroud)
这是可行的,但它也会引发调用时间传递引用警告。
主要问题是__callStatic第二个参数是按值进来的。它正在创建数据的副本,除非该数据已经是引用。
我们可以这样复制调用错误:
call_user_func_array('testFunction', array( $string ));
// PHP Warning: Parameter 1 to testFunction() expected to be a reference, value given
call_user_func_array('testFunction', array( &$string ));
echo $string;
// 'helloworld'
Run Code Online (Sandbox Code Playgroud)
我尝试修改__callStatic方法以通过引用深度复制数组,但这也不起作用。
我非常确定,由 引起的直接复制__callStatic将成为这里的杀手,并且如果没有足够的跳圈使其在语法方面有点粘性,您将无法做到这一点。