Только переменные могут быть переданы по ссылке - PullRequest
17 голосов
/ 03 июня 2010

У меня появилась блестящая идея использовать пользовательский обработчик ошибок, который привел меня в кроличью нору.

Следующий код дает (с пользовательским обработчиком ошибок и без него): Неустранимая ошибка: только переменные могут передаваться по ссылке

function foo(){
    $b=array_pop(array("a","b","c"));
    return $b;
}
print_r(foo());

Следующий код дает ( только с пользовательским обработчиком ошибок ): (2048) Только переменные должны передаваться по ссылке

function foo(){
    $a=explode( '/' , 'a/b/c');
    $c=array_pop(array_slice($a,-2,1));
    return $c;
}
print_r(foo());

Второй беспокоит меня, так как у меня много «компактного» кода. Поэтому я либо отказываюсь от яркой идеи использования собственного обработчика ошибок (для улучшения моего модуля ведения журнала), либо расширяю весь свой код.

Кто-нибудь с лучшими идеями? Также WTF?

UPDATE

Благодаря ответам я кое-что узнал о том, как php обрабатывает ошибки. Неразбериха с E_ALL, за исключением E_STRICT (php 5), не очень крутая.

Помимо всего этого, создание собственного обработчика ошибок по умолчанию включает E_STRICT и именно здесь начинаются проблемы.

Мораль этой истории состоит в том, чтобы использовать собственный обработчик ошибок, чтобы перехватить их ВСЕ и использовать константы ошибок (E_STRICT, E_USER_WARNING, E_USER_ERROR и т. Д.) Для выполнения фильтрации.

Что касается «проблемы повреждения памяти» со ссылками на переменные и некоторыми функциями, что я могу сказать? Вдвойне не круто. Я (что не означает, что вы должны) игнорировать E_STRICT в моем обработчике ошибок, и жизнь продолжается.

Ответы [ 7 ]

18 голосов
/ 03 июня 2010

array_pop () пытается изменить то значение, которое передается в качестве параметра. Теперь во втором примере это возвращаемое значение из array_slice (). В терминах движка это «временное значение», и такое значение не может быть передано по ссылкам. вам нужна временная переменная:

function foo(){
    $a=explode( '/' , 'a/b/c');
    $b=array_slice($a,-2,1);
    $c=array_pop($b);
    return $c;
}
print_r(foo());

Тогда ссылка на $ b может быть передана в array_pop (). См. http://php.net/references для более подробной информации о ссылках.

9 голосов
/ 03 июня 2010

Вот что я получу, когда попробую ваш второй фрагмент кода php в php-cli после установки error_reporting в E_ALL | E_STRICT

    gparis@techosaure:~/workspace/universcine.com$ php -a
Interactive shell

php > function foo(){
php {     $a=explode( '/' , 'a/b/c');
php {     $c=array_pop(array_slice($a,-2,1));
php {     return $c;
php { }
php > print_r(foo());
PHP Strict standards:  Only variables should be passed by reference in php shell code on line 3
PHP Stack trace:
PHP   1. {main}() php shell code:0
PHP   2. foo() php shell code:1

Как видите, здесь только строгие стандарты. И вы можете легко позволить своему пользовательскому обработчику ошибок игнорировать их (в зависимости от значения, которое вы получите: например, 2048 здесь).

Начиная с php 5.3, E_ALL не включает E_STRICT, посмотрите на это:

php > foreach(array("E_ALL", "E_DEPRECATED", "E_STRICT", "E_NOTICE", "E_PARSE", "E_WARNING") as $const) echo $const . "  :\t" . constant($const) ."\t". decbin(constant($const)). "\n";
E_ALL  :        30719   111011111111111
E_DEPRECATED  : 8192     10000000000000
E_STRICT  :     2048       100000000000
E_NOTICE  :     8                  1000
E_PARSE  :      4                   100
E_WARNING  :    2                    10

Начиная с php 5.4, E_ALL включает E_STRICT:

E_ALL  :            32767   111111111111111
E_DEPRECATED  :     8192     10000000000000
E_STRICT  :         2048       100000000000
E_NOTICE  :         8                  1000
E_PARSE  :          4                   100
E_WARNING  :        2                    10
4 голосов
/ 03 июня 2010

Это проблема повреждения памяти (согласно команде разработчиков PHP). Просто добавьте задание:

function foo(){
    $b = array_pop($arr = array("a","b","c"));
    return $b;
}
print_r(foo());

function foo(){
    $a = explode( '/' , 'a/b/c');
    $c = array_pop($arr = array_slice($a,-2,1));
    return $c;
}
print_r(foo());

Второй производит E_STRICT. Вы можете обрабатывать это по-другому в вашем обработчике ошибок, если хотите (если вы не хотите изменять эти функции).

1 голос
/ 26 декабря 2011

Я думаю, что сейчас (начиная с php 5) оно должно быть:

function &foo(){ //NOTICE THE &
    $b=array_pop(array("a","b","c"));
    return $b;
}
print_r(foo());

и

function &foo(){ //NOTICE THE &
    $a=explode( '/' , 'a/b/c');
    $c=array_pop(array_slice($a, $b = -2, $c = 1)); //NOW NO DIRECT VALUES ARE PASSED IT MUST BE VARIABLES
    return $c;
}
print_r(foo());

но я только начинающий :) 1007 *

1 голос
/ 03 июня 2010

array_pop() изменяет это значение, переданное ему, из которого исходит ошибка. Функция не может быть изменена. Другими словами, вам нужно сначала присвоить массив переменной (ref: manual ), а затем запустить array_pop().

Код, который вам нужен:

function foo(){
    $a = array("a","b","c");
    $b = array_pop($a);
    return $b;
}

Редактировать: Обе упомянутые вами функции имеют ту же проблему. Присвойте массив переменной и передайте переменную array_pop().

0 голосов
0 голосов
/ 03 июня 2010

Попробуйте это:

function foo(){
    $a = array("a","b","c");
    $b = array_pop($a);
    return $b;
}
...