В чем разница передачи по значению и по ссылке в PHP
Что проверяют
Знаете ли вы, что происходит с памятью при передаче по значению, и как в эту картину вписываются объекты. Почти всегда следом спрашивают: «А объект в PHP передаётся по ссылке?» и «Ускоряет ли & работу с большим массивом?».
Как отвечать
По умолчанию PHP передаёт аргументы по значению: функция получает свою переменную, и изменения внутри наружу не выходят. Амперсанд в сигнатуре function add(array &$list) делает параметр ссылкой на переменную вызывающего кода, и тогда $list[] = 1 меняет исходный массив.
Сильный ответ отличают три вещи:
- copy-on-write: при передаче по значению массив или строка не копируются сразу. Обе переменные указывают на одно значение со счётчиком ссылок, копия создаётся только в момент записи. Передача большого массива на чтение почти ничего не стоит;
- объекты: в переменной лежит не сам объект, а его идентификатор (handle). Он передаётся по значению, поэтому
$user->name = 'x'внутри функции виден снаружи, а$user = new User()уже нет. Фраза «объекты передаются по ссылке» неточна, это разные механизмы; - синтаксис: ставить
&при вызове,foo(&$x), нельзя с PHP 5.4, это фатальная ошибка. Ссылка объявляется только в сигнатуре. Литерал в такой параметр передать тоже не получится.
Где ссылки уместны: встроенные функции, которые возвращают результат через аргумент (sort(), preg_match() с $matches), foreach ($items as &$item) для правки элементов на месте, замыкание с use (&$counter). В прикладном коде обычно лучше вернуть новое значение: функция остаётся чистой и проще тестируется.
Где спотыкаются
Советуют передавать большие массивы по ссылке «для экономии памяти». Из-за copy-on-write выигрыша нет, а смешение ссылок и значений иногда, наоборот, заставляет движок сделать копию.
Говорят, что объекты передаются по ссылке, и не могут объяснить, почему присвоение параметру нового объекта не меняет переменную снаружи.
Забывают unset($item) после foreach по ссылке. Переменная продолжает указывать на последний элемент, и следующий цикл по тому же массиву молча его перезапишет.