Продвинутые методы работы с массивами через ссылки

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

Основные способы применения ссылок к массивам в PHP

Ссылки в PHP позволяют работать с массивами без создания копий, что важно для оптимизации и изменения исходных данных. Рассмотрим основные варианты использования ссылок.

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

Самый эффективный способ изменить массив внутри функции без возврата нового значения - указать параметр как ссылочный с помощью символа &.


function addElement(array &$arr, $value) {
    $arr[] = $value;
}
$data = [1, 2, 3];
addElement($data, 4);
print_r($data);
  

Php массивы ссылки (ссылки на массивы в php)

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

В этом примере массив $data изменяется непосредственно, без возврата. Это экономит память и позволяет модифицировать исходную структуру.

Типичная ошибка: забыть поставить & перед параметром. В таком случае функция будет работать с копией, и изменения не повлияют на исходный массив. Решение - всегда проверять объявление функции.

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

Можно объявить функцию, возвращающую ссылку, и присвоить результат также по ссылке. Это используется, когда нужно получить доступ к внутреннему массиву объекта или статической переменной.


function &getData() {
    static $stored = ['initial'];
    return $stored;
}
$ref = &getData();
$ref[] = 'added';
print_r(getData());
  
Array
(
    [0] => initial
    [1] => added
)

Следует отметить: возвращать ссылку на локальную переменную (не статическую и не переданную по ссылке) нельзя - PHP выдаст предупреждение, и ссылка будет указывать на уже удалённую переменную.

Ошибка: Notice: Only variable references should be returned by reference. Решение - возвращать только те переменные, которые существуют после выхода из функции (статичные, глобальные, переданные по ссылке).

Как получить ссылку на отдельный элемент массива?

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


$arr = ['a', 'b', 'c'];
$ref = &$arr[1];
$ref = 'modified';
print_r($arr);
  
Array
(
    [0] => a
    [1] => modified
    [2] => c
)

После присвоения $ref и изменения его, элемент массива $arr[1] обновляется.

Проблема: если удалить элемент массива (unset($arr[1])), то ссылка $ref станет висячей и будет указывать на неопределённое значение. При попытке её использовать может возникнуть непредсказуемое поведение. Рекомендуется после удаления элемента обнулить ссылку или не использовать её.

Почему после foreach с &$value остаётся побочный эффект?

При использовании foreach ($arr as &$value) переменная $value после цикла продолжает ссылаться на последний элемент массива. Это может привести к случайным изменениям при последующем использовании $value.


$arr = [1, 2, 3];
foreach ($arr as &$value) {
    $value *= 2;
}
// Не забыть unset($value);
// Теперь случайно присвоим значение:
$value = 100;
print_r($arr);
  
Array
(
    [0] => 2
    [1] => 4
    [2] => 100
)

Как видно, третий элемент изменился, так как $value всё ещё ссылается на него.

Типичная ошибка - забыть вызвать unset($value) после окончания цикла. Решение: всегда сбрасывать ссылку после цикла с помощью unset($value).

Расширенные примеры использования ссылок на массивы

Дополнительные сценарии, демонстрирующие возможности и подводные камни работы с ссылками на массивы в PHP.

Пример 1: Ссылка на элемент многомерного массива

Пример

$matrix = [[1,2], [3,4]];
$ref = &$matrix[0][1];
$ref = 99;
print_r($matrix);
Array
(
    [0] => Array
        (
            [0] => 1
            [1] => 99
        )
    [1] => Array
        (
            [0] => 3
            [1] => 4
        )
)

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

Пример 2: Рекурсивная обработка многомерного массива по ссылке

Пример

function processRecursive(array &$arr) {
    foreach ($arr as &$val) {
        if (is_array($val)) {
            processRecursive($val);
        } else {
            $val += 10;
        }
    }
    unset($val); // важно
}

$nested = [1, [2, [3]]];
processRecursive($nested);
print_r($nested);
Array
(
    [0] => 11
    [1] => Array
        (
            [0] => 12
            [1] => Array
                (
                    [0] => 13
                )
        )
)

Рекурсивная функция принимает массив по ссылке, модифицирует все числовые значения. Важно сбрасывать ссылку $val после каждого цикла, чтобы избежать побочных эффектов.

Пример 3: Использование array_walk с модификацией по ссылке

Пример

$data = [10, 20, 30];
array_walk($data, function (&$item) {
    $item *= 1.5;
});
print_r($data);
Array
(
    [0] => 15
    [1] => 30
    [2] => 45
)

В замыкании, переданном в array_walk, параметр $item объявлен как ссылка, поэтому изменения применяются к оригинальному массиву. Это альтернатива циклу foreach.

Пример 4: Влияние unset на ссылку от элемента массива

Пример

$arr = ['x', 'y', 'z'];
$ref = &$arr[1];
unset($arr[1]);
echo $ref; // что выведется?
var_dump(isset($ref));
y
bool(true)

После удаления элемента массива ссылка всё ещё хранит старое значение, но при этом она не привязана к массиву. isset($ref) вернёт true, так как переменная существует. Однако дальнейшее использование может привести к неожиданностям.

Проблема: если после удаления элемента попытаться присвоить новое значение через $ref, оно не повлияет на массив. Рекомендуется не полагаться на ссылки на удалённые элементы.

Ссылки на массивы в PHP - comments

En
Php массивы ссылки (php)