__ callStatic (), call_user_func_array (), ссылки и PHP 5.3.1

Я читал о 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;

Чтобы вдохновить на возможное решение, я собираюсь добавить здесь сводные детали:

Сосредоточение внимания только на 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 () , и, конечно же, передается по значению как элемент массива в testFunction () через call_user_func_array () . Это приводит к предупреждению, поскольку testFunction () ожидает ссылки.

После взлома всплыли некоторые дополнительные детали. Определение __ callStatic () , если оно написано для возврата по ссылке ( общедоступная статическая функция & __ 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"

Эти результаты ожидаются, поскольку $ test больше не передается по ссылке, изменение не передается обратно в область его действия. Однако это подтверждает, что call_user_func_array () на самом деле работает, как ожидалось, и что проблема определенно ограничена вызывающей магией.

При дальнейшем чтении выясняется, что это может быть «ошибка» в Обработка PHP пользовательских функций и магия __ call () / __ callStatic () . Я просмотрел базу данных ошибок на предмет существующих или связанных проблем и нашел ее, но не смог найти ее снова. Я подумываю о выпуске другого отчета или повторном открытии существующего отчета.

8
задан Beachhouse 18 December 2012 в 16:12
поделиться