Fun PHP #3

Значения по ссылке

Дано:

<?php

function getCount(&$a) { return count($a); }

$cnt = getCount( $foo );
var_dump($cnt);

$cnt = getCount( $foo['bar'] );
var_dump($cnt);

#EOF

Возникает вопрос, а что за $foo ? Отвечаю: не определен. Нет его. Что будет?

Логично же, что ошибка, да?

Нет, не совсем логично. Код отработает без ошибок и предупреждений, если у вас следующие версии интерпретатров:

  • PHP 5.6.0–5.6.30
  • PHP 7.0.0–7.1.13
  • HHVM 3.18.5–3.22.0

При передаче объекта по ссылке, интерпретатор не проверяет его содержимое и структуру. Эта фича существовала до версии PHP 7.2 и уже с этой версии начали генерировать варнинги.

Warning: count(): Parameter must be an array or an object that implements Countable in /in/EV9Fh on line 3 int(0)
Warning: count(): Parameter must be an array or an object that implements Countable in /in/EV9Fh on line 3 int(0)

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

С версии 7.2 начинают сыпаться предупреждения, но они нам говорят о том, что мы передаем значения неверного типа, а не о том, что мы оперируем несуществующими переменными.

Пруф на тест: https://3v4l.org/EV9Fh

Опять же эта задачка в копилку к задаче:

При рефакторинге большого приложения очень сильно может подгадить такое поведение. Но тут надо понимать зачем и как писать такой код и когда стоит пользоваться ссылками, а когда нет.

UPD

Комментарий моего коллеги, с которым я когда-то работал в мамбе (https://www.facebook.com/mipxtx):

До версии 7.2 в функции count() не было проверок типов. Если бы ты обратился в своей функции к переданной переменной на чтение, то получил бы ворнинг так или иначе.

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

Ты передаешь ссылку на элемент массива, указывая таким образом, что хочешь после выполнения получить массив с таким-то элементом. А вообще в пхп нет никакого смысла передавать параметры по ссылкам. Память ты не сэкономишь, они все copy-on-write. А возвращаемый результат функции должен быть одним. Несколько результатов нарушают принципы SOLID напрямую.

Предыдущие задачи