我一直在Stack Overflow和其他地方阅读,但似乎找不到什么确定性的内容。
有没有办法有效地通过此调用堆栈传递引用,从而实现如下示例中所述的所需功能?虽然该示例并未尝试解决该问题,但它确实说明了问题:
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;
为了激发潜在的解决方案,我在这里添加摘要细节:
仅关注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
通过明确将数组元素$test
作为引用传递,我们可以缓解这种情况:
call_user_func_array('testFunction', array(&$test));
var_dump($test);
// string(6) "foobar"
当我们使用
__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"
在
TestClass::testFunction()
中省略引用运算符会导致$test
以传值的方式传递到__callStatic()
,并且当然会通过call_user_func_array()
以数组元素的形式传递到testFunction()
。由于testFunction()
需要一个引用,因此会出现警告。在处理问题时,一些额外的细节浮出水面。如果
__callStatic()
定义为返回引用(public static function &__callStatic()
),则没有明显的影响。此外,将$arguments
数组的元素重新转换为引用,我们可以看到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"
由于$test
不再通过引用传递,因此这些结果是可以预料的,更改不会传回其范围。但是,这证实了call_user_func_array()
确实像预期的那样工作,并且问题肯定局限于调用魔术方法。
进一步阅读后,似乎这可能是PHP处理用户函数和__call()
/__callStatic()
魔术方法的“错误”。我已经查看了现有或相关问题的漏洞数据库,并找到了一个问题,但无法再次定位它。我正在考虑发布另一个报告或请求重新打开现有报告。
__call()
魔术方法有关,而不是call_user_func_array()
...此外,似乎没有特别干净的解决方法。不过,欢迎任何想法。 - Dan Lugg