__callStatic(), call_user_func_array(), references, and PHP 5.3.1

后端 未结 4 1363
温柔的废话
温柔的废话 2021-01-05 01:35

I\'ve been reading around on SO, and elsewhere, however I can\'t seem to find anything conclusive.

Is there any way to effectively carry references through this call

4条回答
  •  爱一瞬间的悲伤
    2021-01-05 01:47

    I'm answering this myself with a step-by-step reproduction of the issue, which demonstrates that it is likely not possible to achieve the desired functionality.

    Our test function is fairly straightforward, and is as follows:

    function testFunction(&$argument)
    {
        $argument++;
    }
    

    If we call the function directly, it, of course, behaves as expected:

    $value = 1;
    testFunction($value);
    var_dump($value); // int(2)
    

    If we call the function using call_user_func_array:

    call_user_func_array('testFunction', [$value]);
    var_dump($value); // int(1)
    

    The value remains at 1, because $value was not passed by reference. We can force this:

    call_user_func_array('testFunction', [&$value]);
    var_dump($value); // int(2)
    

    Which again works as calling the function directly.

    Now, we introduce the class, using __callStatic:

    class TestClass
    {
        public static function __callStatic($name, $argumentArray)
        {
            return call_user_func_array($name, $argumentArray);
        }
    }
    

    If we call the function by forwarding it through __callStatic:

    TestClass::testFunction($value);
    var_dump($value); // int(1)
    

    The value remains at 1, and we also get a warning:

    Warning: Parameter 1 to testFunction() expected to be a reference, value given

    Which verifies that $argumentArray passed into __callStatic does not contain references. That makes perfect sense, as PHP doesn't know the arguments are intended to be accepted by reference in __callStatic, nor that we are forwarding the arguments on.

    If we change __callStatic to accept the array by reference, in an attempt to force the desired behaviour:

    public static function __callStatic($name, &$argumentArray)
    {
        return call_user_func_array($name, $argumentArray);
    }
    

    Uh oh! Spaghetti-O's!

    Fatal error: Method TestClass::__callstatic() cannot take arguments by reference

    Can't do that; besides, that's supported by the documentation anyway:

    Note:
    None of the arguments of these magic methods can be passed by reference.

    Despite not being able to declare __callStatic to accept by reference, if we use call_user_func_array (which would be rather awkward and self-defeating in practice) to forward references through __callStatic:

    call_user_func_array(['TestClass', 'testFunction'], [&$value]);
    var_dump($value); // int(2)
    

    It once again works.

提交回复
热议问题