Сообщение об ошибке Строгие стандарты: по ссылке следует передавать только переменные

$el = array_shift($instance->find(..))

Приведенный выше код каким-то образом сообщает о предупреждении о строгих стандартах, но это не будет:

function get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Так когда же он сообщит о предупреждении в любом случае?


person user198729    schedule 01.03.2010    source источник
comment
Что возвращает $instance-›find(..)?   -  person Silver Light    schedule 01.03.2010
comment
Вот решение: stackoverflow.com/questions/9848295/   -  person ajaristi    schedule 08.03.2013
comment
Я думаю, что примеры (или логика) могут быть неправильными в вопросе, поскольку второй пример (функция get_arr()) действительно создает уведомление о строгих стандартах (проверено PHP 5.2 и PHP 5.5).   -  person MrWhite    schedule 01.05.2014


Ответы (6)


Рассмотрим следующий код:

error_reporting(E_STRICT);
class test {
    function test_arr(&$a) {
        var_dump($a);
    }
    function get_arr() {
        return array(1, 2);
    }
}

$t = new test;
$t->test_arr($t->get_arr());

Это приведет к следующему результату:

Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

Причина? Метод test::get_arr() не является переменной, и в строгом режиме он будет генерировать предупреждение. Такое поведение крайне неинтуитивно, поскольку метод get_arr() возвращает значение массива.

Чтобы обойти эту ошибку в строгом режиме, либо измените сигнатуру метода, чтобы он не использовал ссылку:

function test_arr($a) {
    var_dump($a);
}

Поскольку вы не можете изменить подпись array_shift, вы также можете использовать промежуточную переменную:

$inter = get_arr();
$el = array_shift($inter);
person leepowers    schedule 01.03.2010
comment
@ user198729: Я тоже искал объяснение или исправление и обнаружил, что вы можете использовать current() для первого элемента. Увы, end() не работает для последнего элемента, поскольку он продвигает внутренний указатель к последнему элементу. current(array_reverse(somefunction())) работает (да, это глупо) - person MSpreij; 11.10.2011
comment
Мне нравится обходной путь current(). На самом деле, много раз я ловил себя на том, что использую array_shift(), чего я действительно хочу, так это current(), но это может быть только я. - person Dominic P; 26.07.2013
comment
Использование current предполагает, что указатель массива находится на первом элементе. В большинстве случаев это может быть правильным предположением, но его следует остерегаться. - person cmbuckley; 03.08.2013
comment
@cbuckley - очень верно - поэтому для получения первого элемента следует использовать reset() вместо current(). reset() сбросит внутренний указатель массива и вернет первый элемент массива. - person leepowers; 04.08.2013
comment
@leepowers Конечно, тогда была бы та же проблема, что и array_shift(), поскольку она ожидает, что ссылка будет изменена :-) - person cmbuckley; 05.08.2013
comment
@ user198729 Вы можете избежать значения $intermediate, используя дополнительную пару скобок. $el = array_shift( ( get_arr() ) );. См. stackoverflow.com/questions/9848295/ - person Chloe; 22.10.2015
comment
@Chloe Это самое блестящее решение, которое я видел, чтобы сделать код простым !! Спасибо! - person hargobind; 06.02.2016

$instance->find() возвращает ссылку на переменную.

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

Это помогает предотвратить утечку памяти и, вероятно, станет ошибкой в ​​следующих версиях PHP.

Ваш второй блок кода выдаст ошибку, если он будет написан так (обратите внимание на & в сигнатуре функции):

function &get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Таким образом, быстрое (и не очень приятное) исправление будет таким:

$el = array_shift($tmp = $instance->find(..));

По сути, вы сначала выполняете присвоение временной переменной и отправляете переменную в качестве аргумента.

person Sagi    schedule 01.03.2010
comment
Теперь должно работать (проверено). Чтобы вернуть ссылку, вы должны объявить ее в подписи метода, а не в операторе возврата (моя ошибка). - person Sagi; 01.03.2010
comment
Нет, я не могу изменить подпись. Промежуточная переменная @pygorex1 может решить эту проблему, но выглядит избыточной, не так ли? - person user198729; 01.03.2010
comment
Я знаю, что вы не можете изменить подпись, просто объяснил, как это происходит. Вы должны использовать временную (=промежуточную) переменную, но вы можете сделать это в той же строке. Посмотрите на мой второй фрагмент кода. - person Sagi; 01.03.2010
comment
Я попробовал ваш второй фрагмент, не работает. Он работает только в отдельной строке. - person user198729; 01.03.2010
comment
Верно. Присваивание возвращает присвоенное значение. array_shift($tmp = $instance->find(..)) присваивает значение $instance->find(..) $tmp, а затем передает значение присваивания array_shift(), что не то же самое, что передача самого $tmp, поэтому не лучше исходной ситуации без присвоения. - person phils; 12.02.2014

Причиной ошибки является использование внутренней функции структур данных программирования PHP, array_shift() [php.net/end].

Функция принимает массив в качестве параметра. Хотя в прототипе array_shift() в руководстве указан амперсанд, в расширенном определении этой функции нет никакой предостерегающей документации, а также нет явного объяснения того, что параметр фактически передается по ссылке.

Возможно, это /понято/. Однако я не понял, поэтому мне было трудно определить причину ошибки.

Воспроизвести код:

function get_arr()
{
    return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);
person Biju B Adoor    schedule 25.11.2014

Этот код:

$monthly_index = array_shift(unpack('H*', date('m/Y')));

Необходимо изменить на:

$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);
person user6031348    schedule 07.03.2016

Второй фрагмент тоже не работает, и вот почему.

array_shift — это функция-модификатор, которая изменяет свой аргумент. Поэтому он ожидает, что его параметр будет ссылкой, а вы не можете ссылаться на что-то, что не является переменной. См. пояснения Расмуса здесь: Строгие стандарты: по ссылке должны передаваться только переменные

person user187291    schedule 01.03.2010

Что ж, в таких очевидных случаях вы всегда можете указать PHP подавлять сообщения, используя «@» перед функцией.

$monthly_index = @array_shift(unpack('H*', date('m/Y')));

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

В результате, я уверен, что ваш друг "системный администратор" будет доволен менее загрязненным error.log.

person Julio Marchi    schedule 08.12.2016
comment
Я не знаю, кто проголосовал за этот ответ, но представленное решение ДЕЙСТВИТЕЛЬНО работает, и это стандартная техника PHP. Действительно разочаровывает... В следующий раз я могу больше не отвечать на вопрос... :( - person Julio Marchi; 17.12.2016
comment
Я бы предположил, что это произошло потому, что подавление сообщения об ошибке не решает проблему с кодом. Что вы будете делать, когда этот тип ошибки изменится с E_STRICT на E_ERROR в будущей версии PHP, и ваш код теперь не запускается, а также не выдает никаких ошибок/выводов? - person Luke; 07.03.2017
comment
@TinoDidriksen, я понимаю и согласен с причинами, по которым следует отказаться от некоторых вредных привычек, особенно для новых поколений. Однако ресурс существует для использования, когда (и если) он безопасен в использовании и применим к предлагаемому контексту. Если бы подавитель ошибок @ был упразднен, он был бы удален из самого языка. То же, что и eval (это может быть зло, но у него есть свои цели). Я против не использования каких-то ресурсов, а обобщения совета. Конкретно для предложенного случая использовать его не помешало бы, даже в целях отладки. - person Julio Marchi; 29.08.2017