Ссылки, так же их иногда называют указатели, в PHP — это переменная которая содержит в себе не значение, а адрес ячейки памяти другой переменной. Что бы стало понятнее, представим такой код:
1
2
3
|
$a = 1;
$b = ‘abc’;
$c = $b
|
Выполнение выше приведенных строк интерпретатором PHP, на машинном(низком) уровне, это будет выглядеть примерно вот так:
Адрес ячейки | Значение ячейки |
aff123 | 1 |
aff124 | abc |
aff125 | abc |
Как видно из таблицы, все переменные в PHP являются неким подобием ассоциативного массива, где ключ — это адрес ячейки, а значение — значение переменной.
Так вот ссылка на переменную — это и есть адрес ячейки памяти. Для взятие ссылки в PHP используется символ: ‘&’. Рассмотрим на примере:
1
2
3
4
|
$a = 5;
$b = &$a;
echo $b //выведет — 5
|
Изначально может показаться, что это тоже самое что $b = $a, но на низком уровне, теперь будет такая таблица:
Адрес ячейки | Значение ячейки |
aff123 | 5 |
aff124 | aff123 |
Теперь в нашей ячейки, куда мы передали ссылку, находиться не какое-либо значение, а адрес другой ячейки. И если мы обратимся к переменной, в которой содержится ссылка на другую переменную, то произойдёт в некотором смысле, redirect(перенаправление), на соответствующую переменную:
1
2
3
4
5
|
$a = 5;
$b = &$a;
$b++;
echo $a //выведет — 6
|
Ссылки в PHP могут образовывать бесконечную вложенность, например:
1
2
3
4
5
6
|
$a = 5;
$b = &$a;
$c = &$b;
$c++;
echo $a // выведет — 6
|
Точно так же можно ссылаться на элементы массива:
1
2
3
4
5
|
$arr = [‘a’ => 5];
$b = &$arr[‘a’];
$b++;
echo $arr[‘a’] //выведет — 6
|
Или использовать их в цикле foreach для изменения значений исходного массива:
1
2
3
4
5
6
7
8
9
10
|
$arr = [1, 2, 3];
foreach($arr as &$val)
{
$val++;
}
echo $arr[0]; // выведет — 2
echo $arr[1]; // выведет — 3
echo $arr[2]; // выведет — 4
|
Мы можем осуществлять передачу по ссылке в функции:
1
2
3
4
5
6
7
8
9
|
function test(&link)
{
$link++;
}
$a = 5;
test($a);
echo $a; // выведет — 6
|
В PHP ссылки (указатели) достаточно просты в понимании, но, как правило, используются редко. И из за этого многие разработчики вообще забывают про их существование и не используют их даже там где это нужно, а в некоторых случаях, без указателей вообще невозможно обойтись. Давайте рассмотрим такой случай.
Использование указателей на практике
В каких же случаях нам не обойтись без указателей? Представим такую задачу:
У нас есть строка:
1
|
$str = «app.ext.list.a101 = from-context»;
|
Из неё нужно сформировать такой массив:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Array
(
[app] => Array
(
[ext] => Array
(
[list] => Array
(
[a101 ] => from—context
)
)
)
)
|
Получается многомерный (вложенный) массив, при этом строка динамическая, т.е. количество элементов массива и индексы мы заранее не знаем, соответственно задача следующая: сформировать динамический многомерный массив (от автора: похожее задание, правда немного сложнее, было выслано мне в качестве тестового задания при устройстве на работу PHP — программистом, так что если вы планируете в ближайшее время трудоустраиваться, рекомендую самостоятельно выполнить это задание и поделиться в комментариях результатом).
Конструкции типа:
1
|
$arr[$key1][$key2][$key3]
|
мы использовать не можем, так как не знаем заранее количество вложенности. Соответственно вложенные цикл foreach мы тоже не можем использовать. Остается единственный вариант: попытаться сформировать подобный массив в одном цикле (не считая цикла перебора ключей строки). Сразу приведу готовый скрипт:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
$str = «app.ext.list.a101 = from-context»;
$arr_value = explode(‘=’, $str);
$arr_indexs = explode(‘.’, $arr_value[0]);
$result=null;
$last_index = null;
foreach($arr_indexs as $val)
{
if(!is_array($result))
{
$result = [];
$result[$val] = ‘qwe’;
$local_mass = &$result;
}
else
{
foreach($local_mass as &$val2)
{
$val2 = [];
$val2[$val] = ‘qwe’;
$local_mass = &$val2;
}
}
$last_index = $val;
}
$local_mass[$last_index] = $arr_value[1];
print_r($result);
|
В строках 1-3, думаю все понятно, формируем наш массив ключей и одно итоговое значение, которое так же храниться в массиве. В 8-ой строке открываем цикл foreach для массива ключей, полученных из строки. Сразу проверяем, является ли переменная $result массивом, если нет то объявляем массив с ключом $val и в переменную $local_mass присваиваем ссылку на этот массив, для того что бы в дальнейшем мы могли через $local_mass менять значения в result. Данное условие сработает в true только один раз, при первой итерации цикла. Все последующие итерации попадают в ветку else (основа нашего алгоритма). Здесь мы выполняем цикл foreach для переменной которая содержит ссылку на основной массив. В качестве значения $val2 так же берем ссылку. Внутри цикла объявляем ссылку $val2 в качестве массива и присваеваем соответственно ключ и значение. Так же обязательно перезаписываем переменную $local_mass на ссылку созданного массива. Таким образом получается, что при каждом обходе цикла($local_mass) мы формируем новую вложенность в исходном массиве $result. Ну а дальше всё просто, в переменную $last_index попадет последний ключ массива, а переменная $local_mass будет является этим массивом, куда мы и запишем итоговое значение. Результат выполнения данного кода:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
Array
(
[app] => Array
(
[ext] => Array
(
[list] => Array
(
[a101 ] => from—context
)
)
)
)
|
Пишите в комментариях отзывы и вопросы, а так же делитесь своими результатами, если вы самостоятельно выполнили данную задачу.