Для начала я понимаю программирование и объекты, но следующее не имеет большого смысла для меня в PHP.
В PHP мы используем оператор & для получения ссылки на переменную. Я понимаю ссылку как способ ссылаться на ту же «вещь» с другой переменной. Если я скажу, например
$b = 1; $a =& $b; $a = 3; echo $b;
будет выводить 3, потому что изменения, сделанные в $ a, совпадают с изменениями, внесенными в $ b. Наоборот:
$b = 1; $a = $b; $a = 3; echo $b;
должен выводить 1.
Если это так, почему ключевое слово clone необходимо? Мне кажется, что если я установил
$obj_a = $obj_b
то изменения, сделанные в $ obj_a, не должны влиять на $ obj_b, наоборот $ obj_a = & $ obj_b должен указывать на тот же объект, поэтому изменения, сделанные в $ obj_a, влияют на $ obj_b.
Однако на PHP кажется, что некоторые операции над $ obj_a DO влияют на $ obj_b, даже если они назначены без ссылочного оператора ($obj_a = $obj_b)
. Это вызвало разочаровывающую проблему для меня сегодня при работе с объектами DateTime, которые я в конечном итоге исправил, выполнив в основном:
$obj_a = clone $obj_b
Но большая часть кода PHP, который я пишу, похоже, не требует явного клонирования, как в этом случае, и отлично работает без него. Что тут происходит? И почему PHP должен быть таким неуклюжим?
В принципе, есть два способа работы переменных в 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 (это означает, что все переменные, указывающие на него, либо выходят за пределы области видимости, либо меняются на somethign else), они собираются с мусором (поскольку они больше не доступны) …
Вы можете больше узнать о ссылках и PHP в документах …
Отказ от ответственности: некоторые из них могут быть упрощением или размытием определенных понятий. Я намеревался это только для того, чтобы быть руководством к тому, как они работают, а не точная разбивка того, что происходит внутри страны …
Редактировать: О, и поскольку это «неуклюжий», я не думаю, что это так. Я думаю, что это действительно полезно. В противном случае вам будут передаваться переменные ссылки по всему месту. И это может привести к некоторым действительно интересным ошибкам, когда переменная в одной части приложения влияет на другую переменную в другой части приложения. И не потому, что это прошло, а потому, что ссылка была сделана где-то вдоль линии.
В общем, я не очень часто использую переменные ссылки. Очень редко я нахожу их честной. Но я все время использую ссылки на объекты. Я использую их так много, что я рад, что они по умолчанию. В противном случае мне нужно будет написать некоторый оператор (так как &
обозначает ссылку на переменную, для обозначения ссылки на объект должна быть другая). И учитывая, что я редко использую clone
, я бы сказал, что 99,9% случаев использования должны использовать ссылки на объекты (чтобы заставить оператора использоваться для случаев с более низкой частотой) …
JMHO
Я также создал видео, объясняющее эти различия. Проверьте это на YouTube .
В PHP 5+ объекты передаются по ссылке. В PHP 4 они передаются по значению (поэтому у него было время выполнения по ссылке, которое устарело). Итак, вы должны использовать оператор clone
в PHP5 для копирования объектов:
$objectB = clone $objectA;
Также обратите внимание, что это просто объекты, которые передаются по ссылке, а не другие переменные. Следующие могут убрать вас больше:
я написал презентацию, чтобы лучше объяснить, как php управляет памятью с помощью своих переменных:
взглянуть 😉