Повідомлення про помилку "Суворі стандарти: Посилання повинні передавати лише змінні"


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

Вищезазначений код якимось чином повідомляє про суворі попередження про стандарти, але це не буде:

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

То коли воно все одно повідомить про попередження?


1
Що повертає $ instance-> find (..)?
Silver Light


Я думаю, що приклади (або логіка) можуть бути неправильними в питанні, оскільки другий приклад ( get_arr()функція) справді подає суворе сповіщення про стандарти (перевірені PHP 5.2 та PHP 5.5).
MrWhite

Відповіді:


93

Розглянемо такий код:

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);

7
@ user198729: Я теж шукав пояснення чи виправлення, і виявив, що ти можеш використовувати current () для першого елемента. На жаль, end () не працює останнє, оскільки "переводить внутрішній вказівник на останній елемент". current (array_reverse (somefunction ())) працює (так, це безглуздо)
MSpreij

1
Використання currentробить припущення, що покажчик масиву знаходиться на першому елементі. У більшості випадків це може бути вагомим припущенням, але варто дотримуватися цього.
cmbuckley

1
@leepowers Звичайно, тоді буде та сама проблема, що і array_shift()в тому, що вона очікує на зміну посилання :-)
cmbuckley

1
@ user198729 Ви можете уникнути $intermediateзначення, використовуючи додаткову пару дужок. $el = array_shift( ( get_arr() ) );. Дивіться stackoverflow.com/questions/9848295/…
Хлоя

1
@Chloe Це найкраще рішення, яке я бачив для простоти коду !! Дякую!
hargobind

7

$instance->find() повертає посилання на змінну.

Ви отримуєте звіт, коли намагаєтесь використовувати це посилання як аргумент функції, не зберігаючи його спочатку у змінній.

Це допомагає запобігти витоку пам'яті і, можливо, стане помилкою в наступних версіях PHP.

Ваш другий блок коду видасть помилку, якщо він напише як (зверніть увагу на &підпис функції):

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

Тож швидким (і не таким приємним) виправленням буде:

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

В основному, ви спочатку призначаєте тимчасовій змінній і надсилаєте змінну як аргумент.


Він повинен працювати зараз (перевірив). Для того, щоб повернути посилання, ви повинні оголосити його підписом методу, а не повернути заяву (моя вина)
Сагі

Ні, я не можу змінити підпис. Проміжна змінна @ pygorex1 може це вирішити, але це виглядає зайвим, чи не так?
user198729

Я знаю, що ти не можеш змінити підпис, просто пояснив, як це відбувається. Ви повинні використовувати тимчасову (= проміжну) змінну, але ви можете зробити це в тому ж рядку. Подивіться на мій другий фрагмент коду.
Сагі

4
Я спробував ваш другий фрагмент, не працює. Він працює лише в окремому рядку
user198729

3
Справді. Призначення повертає присвоєне значення . array_shift($tmp = $instance->find(..))привласнює значення $instance->find(..)для $tmpі потім передає значення завдання на array_shift()- , який не те ж саме, передаючи $tmpсебе, так не краще вихідної ситуації без поступки.
phils

6

Причиною помилки є використання внутрішньої функції програм програмування PHP функції array_shift () [php.net/end].

Функція приймає масив як параметр. Незважаючи на те, що амперсанд вказаний у прототипі array_shift()в посібнику ", у розширеному визначенні цієї функції не існує жодної попереджувальної документації, ані явного пояснення того, що параметр насправді передається за допомогою посилання.

Можливо, це / зрозуміло /. Однак я не зрозумів, тому мені було важко виявити причину помилки.

Код відтворення:

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

3

Цей код:

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

Потрібно змінити на:

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

3

Другий фрагмент теж не працює, і саме тому.

array_shiftє функцією модифікатора, яка змінює свій аргумент. Тому він очікує, що його параметр буде посиланням, і ви не можете посилатися на щось, що не є змінною. Див. Пояснення Расмуса тут: Строгі стандарти: Тільки змінні повинні передаватися за посиланням


0

Ну, у таких очевидних випадках ви завжди можете сказати PHP придушити повідомлення, використовуючи "@" перед функцією.

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

Можливо, це не одна з найкращих практик програмування, щоб придушити всі помилки таким чином, але в певних випадках (як цей) це дуже зручно і є прийнятним.

Як результат, я впевнений, що ваш “системний адміністратор” буде задоволений менш забрудненим error.log.


Я не знаю, хто голосував за цю відповідь, але представлене рішення ДІЄ, і це стандартна техніка PHP. Дійсно розчаровує ... Наступного разу, можливо, я вже не відповім на питання ... :(
Хуліо Марчі

5
Я вважаю, що це тому, що придушення повідомлення про помилку не вирішує проблему з кодом. Що ви зробите, коли цей тип помилки зміниться з E_STRICT на E_ERROR у наступному PHP-випуску, і ваш код тепер не працює, а також не видає помилок / результатів?
Лука

@TinoDidriksen, я розумію і погоджуюся з причинами, щоб відмовитись від деяких "шкідливих звичок", особливо для нових поколінь. Однак існує ресурс, який слід використовувати, коли (і якщо) він безпечний у використанні та застосовується до запропонованого контексту. Якби придушувач помилок "@" було скасовано, його було б видалено з самої мови. Те саме, що і "eval" (це може бути злом, але воно має свої цілі). Я проти, не стосовно використання деяких ресурсів, а узагальнення порад. В конкретному для пропонованого випадку, не було б шкоди використовувати його, навіть для цілей налагодження.
Хуліо Марчі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.