За замовчуванням аргументи передаються за значенням: функція отримує копію, і зміна параметра не впливає на змінну викликача. Знак & у сигнатурі робить передачу за посиланням:
function addItem(array &$cart, string $item): void
{
$cart[] = $item;
}
$cart = [];
addItem($cart, 'книга');
// $cart === ['книга']
Де це в стандартній бібліотеці: sort(), array_push(), preg_match() (масив збігів), array_walk() - вони змінюють передану змінну.
Чому у власному коді це часто погана ідея:
- Прихований побічний ефект. З виклику
addItem($cart, 'книга')не видно, що$cartзміниться. Читач має знати сигнатуру. - Важче міркувати й тестувати: функція не просто повертає результат, а змінює стан ззовні.
- Не дає економії пам'яті. Масиви копіюються ліниво (copy-on-write), тож передача за значенням не копіює дані, доки їх не змінять.
- Не можна передати вираз:
addItem([], 'x')чиaddItem(getCart(), 'x')- помилка, потрібна саме змінна.
Краща альтернатива - повертати нове значення:
function withItem(array $cart, string $item): array
{
return [...$cart, $item];
}
$cart = withItem($cart, 'книга');
Або - об'єкт зі станом і методом: $cart->add('книга') - зміна очевидна з виклику.
Об'єкти й так не копіюються: функція, що отримала об'єкт, працює з тим самим об'єктом. & для об'єкта потрібен лише тоді, коли функція має замінити змінну іншим об'єктом.
Коли посилання виправдані: зміна великих вкладених структур на місці в гарячому коді та рідкісні API на кшталт «повернути кілька значень» - хоча тут читабельніше повернути масив чи об'єкт.
Докладніше в документації: Передача аргументів за посиланням