В сущности, в PHP есть два способа работы с переменными ...
Для всего, кроме объектов:
- Назначение по значению (то есть, если вы делаете копию
$a = $b
.
- Ссылка может быть достигнута с помощью
$a = &$b
(обратите внимание, что оператор ссылки работает с переменной, а не с оператором присваивания, поскольку вы можете использовать его в других местах) ...
- При копировании используется техника копирования при записи. Так что если вы сделаете
$a = $b
, в памяти не будет копии переменной. Но если вы выполните $a = 5;
, память будет скопирована и перезаписана.
Для объектов:
- Назначение по ссылке на объект. Это не то же самое, что нормальная переменная по ссылке (я объясню почему позже).
- Копировать по значению можно, выполнив
$a = clone $b
.
- Ссылка может быть достигнута с помощью
$a = &$b
, но имейте в виду, что это не имеет никакого отношения к объекту. Вы связываете переменную $a
с переменной $b
. Неважно, объект это или нет.
Итак, почему присвоение объектам не является референсным? Что произойдет, если вы сделаете:
$a = new stdclass();
$b = $a;
$a = 4;
Что такое $b
? Ну, это stdclass
... Это потому, что это не запись ссылки на переменную, а на объект ...
$a = new stdclass();
$a->foo = 'bar';
$b = $a;
$b->foo = 'baz';
Что такое $a->foo
? Это baz
. Это потому, что когда вы сделали $b = $a
, вы говорите PHP использовать тот же экземпляр объекта (отсюда и ссылку на объект). Обратите внимание, что $a
и $b
не являются одной и той же переменной, но они оба ссылаются на один и тот же объект.
Один из способов думать об этом - думать о всех переменных, которые хранят объект, как о сохранении указателя на этот объект. Таким образом, объект живет где-то еще. Когда вы назначаете $a = $b
, где $b
- объект, все, что вы делаете, это копируете этот указатель. Фактические переменные все еще не пересекаются. Но когда вы делаете $a = &$b
, вы сохраняете указатель на $b
внутри $a
. Теперь, когда вы манипулируете $a
, он соединяет цепочку указателей с базовым объектом. Когда вы используете оператор clone
, вы говорите PHP скопировать существующий объект и создать новый с тем же состоянием ... Так что clone
на самом деле просто делает копию по значению varaible ...
Так что, если вы заметили, я сказал, что объект не хранится в фактической переменной. Он хранится где-то еще, и в переменной ничего не хранится, кроме указателя. Таким образом, это означает, что вы можете иметь (и часто имеете) несколько переменных, указывающих на один и тот же экземпляр. По этой причине внутреннее представление объекта содержит refcount
(просто подсчет количества переменных, указывающих на него). Когда значение refcount объекта падает до 0 (это означает, что все переменные, указывающие на него, либо выходят из области видимости, либо заменяются другими значениями), он собирается для сбора (так как он более недоступен) ...
Подробнее о ссылках и PHP вы можете прочитать в документации ...
Отказ от ответственности: Отчасти это может быть упрощением или размытием некоторых понятий. Я хотел, чтобы это было лишь руководством к тому, как они работают, а не точным описанием того, что происходит внутри ...
Редактировать: О, и что касается того, что это "неуклюжий", я не думаю, что это так. Я думаю, что это действительно полезно. В противном случае вы будете иметь ссылки на переменные повсюду. И это может привести к некоторым действительно интересным ошибкам, когда переменная в одной части приложения влияет на другую переменную в другой части приложения. И не потому, что оно прошло, а потому, что ссылка была сделана где-то вдоль линии.
В общем, я не так часто использую ссылки на переменные. Редко я нахожу в них искреннюю потребность. Но я все время использую ссылки на объекты. Я использую их так много, что я счастлив, что они по умолчанию. В противном случае мне нужно написать какой-нибудь оператор (так как &
обозначает ссылку на переменную, должен быть другой, чтобы обозначить ссылку на объект). И, учитывая, что я редко использую clone
, я бы сказал, что в 99,9% случаев использования должны использоваться ссылки на объекты (поэтому используйте оператор для более низких частот) ...
JMHO
Я также создал видео, объясняющее эти различия. Проверьте это на YouTube .