Chevy | Дата: Среда, 24.08.2011, 15:30 | Сообщение # 1 |
|
Администраторы |
Генералиссимус |
"Нет титула" |
Сообщений: 85 |
|
|
Offline |
| Данная статья предназначена для тех программистов, кто имеет опыт программирования в других языках и только начал изучать PHP, и для тех из начинающих, кто уже уверенно понимает суть языка и его основные примитивы (синтаксис, переменные, функции, типы данных).
Многие программисты, которые пришли в PHP из компилируемых языков (таких, как C и Pascal), невольно путают ссылки в PHP с указателями. В то же время, начинающие программисты без опыта вообще не понимают, что такое ссылки и как их использовать.
Терминология в статье
В данной статье используются следующие термины: Переменная - Переменная PHP ($foo) или обращение к элементу массива ($foo['bar'][3]). Другими словами - это то, что можно передать в синтаксические конструкии isset(), unset(), empty() и т.п. Значение - значение, которое хранится в Переменной. Таблица переменных, Таблица - некий логический объект для визуального представления происходящего.
Таблица переменных
Где-то в недрах ядра PHP существует Таблица переменных. В этой Таблице в том или ином виде хранятся Переменные, Значения, и связь между ними. Для наглядности Таблицу переменных можно представить следующим образом:
Рис.1
В левой половине - Переменные, в правой - Значения. Стрелки показывают связь Переменной со Значением. В данной примере изображены две переменные: Код PHP
$foo = 2; $bar = 'lol'; Важно Стрелки символизируют одностороннюю связь: Переменной важно знать свое Значение, но Значению совершенно все равно, к какой(-им) Переменной оно принадлежит. Связь (стрелка на изображении) может идти только от Переменной только к Значению. Каждая Переменная всегда имет ровно одну связь (ссылается на одно Значение). Итак, давайте разбираться.
Простейшая ситуация
Самая простая ситуация со ссылками записывается кодом так: Код PHP
$foo = 5; $bar = &$foo; После выполнения 1-й строки в Таблицу переменных заносится Переменная $foo и ее Значение 5. Выполнение 2-й строки создает Переменную $bar и устанавливает связь со Значением Переменной $foo, как показано на Рис.2 красной стрелкой.
Рис.2
Что это значит? Операция присваивания по ссылке заставляет Переменную ссылаться на уже существующее Значение другой Переменной. Обычное присваивание в существующую Переменную изменяет ее существующее Значение. Обычное присваивание в несуществующую Переменную создает новое Значение в Таблице.
А теперь вполне логичный вопрос: Чем отличаются между собой связи, изображенные на Рис.2? Ответ: ничем, они абсолютно одинаковы. Если в коде выше поменять переменные местами: Код PHP
$bar = 5; $foo = &$bar; то Таблица переменных будет выглядеть абсолютно так же (если не брать в расчет порядок создания Переменных).
Более того, каждое Значение знает, сколько Переменных на него ссылаются (количество стрелок на рисунке). В литературе это число называется счетчик ссылок (references counter).
Удаление Переменных
Продолжаем манипуляции над Таблица переменных, изображенной на Рис.2. Удаляем первую переменную после создания ссылки: Код PHP
$foo = 5; $bar = &$foo; unset($foo); Это изменение отобразится в Таблице следующим образом:
Рис.3
Оператор unset() удаляет Переменную и исходящую от нее связь. Почему же при этом не удаляется Значение 5? Потому что еще остались другие Переменные, которые на него ссылаются.
Далее удаляем вторую переменную: Код PHP 1 unset($bar); Аналогично, из Таблицы удаляется Переменная $bar и ее связь со значением. После этого оказывается, что у Значения количество ссылок стало равным нулю, а это значит, что данное Значение тоже удаляется (Рис.4).
Рис.4
Массивы
Более сложные для понимания вещи поджидают нас при махинациях с массивами. Итак, создаем простой массив с тремя элементами: Код PHP 1 $arr = array(1 => 10, 2 => 20, 3 => 30); Как его отобразить в Таблице переменных? Весь массив целиком - это Значение, ибо на него ссылается Переменная $arr. Также, можно заставить другую Переменную ссылаться на Значение любого элемента массива, поэтому 10, 20 и 30 - также должны быть отдельными Значениями.
Рис.5
Здесь #1 - это некий идентификатор массива для внутреннего представления.
Чтобы прочитать значение элемента массива Код PHP 1 echo $arr[2]; необходимо пройти через две связи в Таблице.
Ссылки и Массивы
Итак, к только что созданному массиву начинаем применять ссылки: Код PHP
$arr = array(1 => 10, 2 => 20, 3 => 30); $foo = &$arr; $bar = &$arr[2]; Поскольку мы уже знаем, как расположить массив в Таблице переменных, добавить две Переменные со ссылками на существующие Значения не составит труда.
Рис.6
Затем выполняем обычное присваивание: Код PHP 1 $arr[1] = $arr[2]; Порядок действий таков: Для правой части присваивания в Таблице ищем Переменную $arr - находим массив #1. В массиве #1 ищем элемент с ключем 2 - находим Значение 20. Для левой части аналогично ищем Переменную $arr - находим массив #1. Аналогично в массиве #1 ищем элемент с ключем 1 - находим Значение 10. В найденное в п.4 Значение 10 копируем найденное в п.2 Значение 20.
Перечисленным действиям соответствуют оранжевые цифры на Рисунке 7.
Рис.7
Далее делаем присваивание по ссылке: Код PHP 1 $arr[2] = &$arr[3]; Существующая связь от Переменной #1[2] разрывается и создается новая связь до Значения 30.
Рис.8
Если теперь уничтожить переменную $arr Код PHP 1 unset($arr); то из Таблицы будет удалена соответвтсующая Переменная и ее связь. Поскольку на Значение #1 все еще ссылается другая Переменная, то оно не будет уничтожено.
Рис.9
Последний шаг порождает более интересные вещи: Код PHP 1 $foo = 42; Значение #1, на которое ссылается Переменная $foo, заменяется новым Значением 42. Что значит "заменяется"? Это значит, что старое #1 удаляется. Это приводит к удалению Переменных #1[1], #1[2] и #1[3] вместе с их связями. Тут же оказываются бесхозными два Значения, поэтому они тоже удаляются.
Рис.10
В результате остается две простых пары Переменная - Значение.
|
|
| |