Как работает передача по ссылке в PHP и где это применяется

Раздел: PHP основы -> Переменные и ссылки

Передача значения по ссылке в PHP

В PHP существует несколько способов передачи значений в функции и между переменными. Основной механизм передачи по ссылке позволяет изменять оригинальную переменную внутри функции, не создавая её копию. Это особенно полезно для больших данных, когда копирование ресурсоёмко, или когда необходимо изменить исходные данные из нескольких мест.

Основной способ: амперсанд (&) в объявлении функции

Как сделать, чтобы функция изменяла переданную переменную без копирования?

Для передачи по ссылке в объявлении параметра ставится символ & перед именем переменной. При вызове функции передаётся сама переменная (без & перед аргументом).


function addItem(&$array, $item) {
    $array[] = $item;
}
$list = [1, 2];
addItem($list, 3);
print_r($list);

Php значение по ссылке (передача значения по ссылке в php)

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
)

Частая ошибка:

Попытка передать по ссылке результат выражения (например, addItem(1+2, 3)). Параметр-ссылка требует переменную, а не значение. Если передать литерал или результат вычислений, PHP выдаст фатальную ошибку: Only variables should be passed by reference.

Передача объектов: автоматическая ссылка

Как в PHP ведут себя объекты при передаче в функцию – по значению или по ссылке?

Объекты в PHP (начиная с PHP 5) всегда передаются по идентификатору объекта (фактически по ссылке). Изменения свойств объекта внутри функции влияют на оригинальный объект. Однако сама переменная (ссылку на объект) изменить нельзя – для этого требуется явная ссылка (&).


class User {
    public $name;
}
function renameUser($userObj, $newName) {
    $userObj->name = $newName;
}
$u = new User();
$u->name = 'Alice';
renameUser($u, 'Bob');
echo $u->name; // Bob
Bob

Ошибка путаницы:

Новички часто думают, что объект передаётся полностью по ссылке, но если внутри функции написать $userObj = null, то внешняя переменная не станет null. Для полного управления ссылкой на объект нужно передавать его по явной ссылке (function renameUser(&$userObj)).

Передача массива по ссылке

Как изменить массив внутри функции без копирования всех его элементов?

Массивы по умолчанию передаются по значению. Для изменения оригинального массива внутри функции используется ссылка (&).


function removeLast(&$arr) {
    array_pop($arr);
}
$data = [10, 20, 30];
removeLast($data);
print_r($data);
Array
(
    [0] => 10
    [1] => 20
)

Проблема с копированием больших массивов:

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

Использование ссылок в цикле foreach

Как изменить элементы массива непосредственно во время обхода?

В PHP можно передавать элемент по ссылке внутри foreach. Это позволяет модифицировать исходный массив без создания временной копии.


$numbers = [1, 2, 3];
foreach ($numbers as &$value) {
    $value *= 2;
}
unset($value); // важно сбросить ссылку
print_r($numbers);
Array
(
    [0] => 2
    [1] => 4
    [2] => 6
)

Типичная ошибка: забыли unset($value)

После цикла переменная $value продолжает ссылаться на последний элемент массива. Если дальше использовать $value неосторожно, можно случайно изменить этот элемент. Всегда следует вызывать unset($value) после такого цикла.

Передача по ссылке в вызывающем коде

Как принудительно передать переменную по ссылке, если функция ожидает передачу по значению?

Можно использовать оператор & перед переменной в месте вызова функции, даже если параметр объявлен без ссылки. Однако такой подход считается устаревшим (deprecated начиная с PHP 5.3). Лучше изменять объявление функции.


function double($num) {
    $num *= 2;
}
$value = 5;
double(&$value); // устаревший синтаксис
echo $value; // 5 (не изменилось!)
5

Проблемы устаревшего синтаксиса:

В PHP 7 вызов с & перед переменной уже вызывает предупреждение Deprecated: Call-time pass-by-reference has been deprecated. В PHP 8 это приводит к фатальной ошибке. Настоятельно не рекомендуется использовать этот метод.

Ссылка на переменную через оператор =&

Как создать псевдоним для переменной, чтобы обе переменные указывали на одно и то же значение?

Оператор =& позволяет сделать переменную ссылкой на другую переменную. Изменение одной приводит к изменению другой.


$a = 100;
$b =& $a;
$b = 200;
echo $a; // 200
200

Неявные ссылки:

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

Расширенные примеры передачи по ссылке

Пример 1: Рекурсивная функция с ссылкой

Для рекурсивного изменения всех элементов вложенного массива передача по ссылке обязательна.

Пример

function addPrefix(&$arr, $prefix) {
    foreach ($arr as &$value) {
        if (is_array($value)) {
            addPrefix($value, $prefix);
        } else {
            $value = $prefix . $value;
        }
    }
    unset($value);
}
$config = [
    'db' => ['host' => 'localhost'],
    'app' => ['name' => 'Test']
];
addPrefix($config, 'prefix_');
print_r($config);
Array
(
    [db] => Array
        (
            [host] => prefix_localhost
        )
    [app] => Array
        (
            [name] => prefix_Test
        )
)

Пример 2: Передача по ссылке в анонимных функциях (closures)

Анонимные функции могут захватывать внешние переменные по ссылке с помощью use (&$var).

Пример

$counter = 0;
$increment = function() use (&$counter) {
    $counter++;
};
$increment();
$increment();
echo $counter; // 2
2

Пример 3: Функция с переменным числом аргументов и ссылками

Используем ... (spread) для передачи переменного количества ссылок.

Пример

function sumAll(&...$numbers) {
    $sum = 0;
    foreach ($numbers as &$n) {
        $sum += $n;
        $n = 0; // обнуляем каждый элемент
    }
    return $sum;
}
$a = 10;
$b = 20;
$c = 30;
$total = sumAll($a, $b, $c);
echo "Сумма: $total\n";
echo "a=$a, b=$b, c=$c";
Сумма: 60
a=0, b=0, c=0

Пример 4: Ссылка на статическую переменную внутри функции

Статические переменные можно сделать ссылкой для сохранения состояния между вызовами.

Пример

function &getStaticVar() {
    static $value = 0;
    return $value;
}
$ref =& getStaticVar();
$ref = 42;
getStaticVar() = 100; // можно даже присвоить напрямую
echo getStaticVar(); // 100
100

Пример 5: Передача по ссылке в глобальном пространстве

Глобальные переменные внутри функции можно привязать через global $var или явную ссылку.

Пример

$globalVar = 'original';
function modifyGlobal(&$var) {
    $var = 'modified';
}
modifyGlobal($globalVar);
echo $globalVar; // modified
modified

Пример 6: Использование ссылки для модификации элементов коллекции объектов

Пример

class Item {
    public $name;
}
$items = [new Item(), new Item()];
$items[0]->name = 'First';
$items[1]->name = 'Second';

function renameItems(array &$list, $prefix) {
    foreach ($list as $item) {
        $item->name = $prefix . $item->name;
    }
}
renameItems($items, 'New_');
echo $items[0]->name . ", " . $items[1]->name; // New_First, New_Second
New_First, New_Second

Передача значения по ссылке в PHP - comments

En
Php значение по ссылке (php)