В PHP Может ли кто-нибудь объяснить клонирование по отношению к указателю?

Для начала я понимаю программирование и объекты, но следующее не имеет для меня особого смысла в 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, Если я скажу, например,

$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, Если я скажу, например,

$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 должен быть таким неуклюжим ??

18
задан shamittomar 31 August 2010 в 18:24
поделиться

2 ответа

В принципе, есть два способа работы переменных в PHP...

Для всего, кроме объектов:

  1. Присваивание по значению (это означает, что копирование происходит, если вы делаете $a = $b
  2. Ссылку можно получить, выполнив $a = &$b (обратите внимание, что оператор ссылки работает с переменной, а не с оператором присваивания, поскольку вы можете использовать его в других местах)...
  3. Копии используют метод копирования при записи. Поэтому, если вы сделаете $a = $b, копии переменной в памяти не будет. Но если вы затем сделаете $a = 5; , затем память копируется и перезаписывается

Для объектов:

  1. Присваивание осуществляется по ссылке на объект. Это не совсем то же самое, что обычная переменная по ссылке (позже я объясню почему).
  2. Копировать по значению можно получить, выполнив $a = clone $b.
  3. Ссылку можно получить, выполнив $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? Это баз. Это потому, что когда вы сделали $b = $a, вы говорите PHP использовать тот же экземпляр объекта (отсюда и ссылка на объект).Обратите внимание, что $a и $b не являются одной и той же переменной, но обе они ссылаются на один и тот же объект.

Один из способов думать об этом — думать обо всех переменных, в которых хранится объект, как о хранящих указатель на этот объект. Значит, объект живет где-то еще. Когда вы присваиваете $a = $b, где $b — объект, все, что вы делаете, — это копируете этот указатель. Фактические переменные по-прежнему не пересекаются. Но когда вы делаете $a = &$b, вы сохраняете указатель на $b внутри $a. Теперь, когда вы манипулируете $a, он каскадирует цепочку указателей на базовый объект. Когда вы используете оператор clone, вы указываете PHP скопировать существующий объект и создать новый с тем же состоянием... Так что clone на самом деле просто делает копия значения переменной...

Итак, если вы заметили, я сказал, что объект не хранится в фактической переменной. Он хранится где-то еще, и в переменной хранится только указатель. Это означает, что вы можете иметь (и часто имеете) несколько переменных, указывающих на один и тот же экземпляр. По этой причине внутреннее представление объекта содержит refcount (просто количество переменных, указывающих на него). Когда счетчик ссылок объекта падает до 0 (это означает, что все переменные, указывающие на него, либо выходят из области видимости, либо изменяются на что-то другое), он удаляется из мусора (поскольку он больше не доступен)...

Вы можете прочитать подробнее о ссылках и PHP в документации...

Отказ от ответственности: Частично это может быть чрезмерным упрощением или размытием некоторых понятий. Я хотел, чтобы это было только руководством к тому, как они работают, а не точным описанием того, что происходит внутри...

Изменить: О, а что касается "неуклюжести", я не думаю Это. Я думаю, что это действительно полезно. В противном случае ссылки на переменные будут передаваться повсюду. И это может привести к некоторым действительно интересным ошибкам, когда переменная в одной части приложения влияет на другую переменную в другой части приложения. И не потому, что это прошло, а потому, что где-то по ходу дела была сделана ссылка.

В общем, я не так часто использую ссылки на переменные. Редко когда я нахожу в них честную потребность. Но я все время использую ссылки на объекты. Я использую их так много, что я счастлив, что они по умолчанию. В противном случае мне нужно было бы написать некоторый оператор (поскольку & обозначает ссылку на переменную, должен быть еще один для обозначения ссылки на объект). И учитывая, что я редко использую клон, я бы сказал, что в 99,9% случаев использования должны использоваться ссылки на объекты (так что оператор должен использоваться для случаев с более низкой частотой)...

JMHO

Я также создал видео, объясняющее эти различия. Посмотрите на YouTube.

44
ответ дан 30 November 2019 в 06:25
поделиться

Коротко:

В PHP 5+ объекты передаются по ссылке. В PHP 4 они передаются по значению (поэтому во время выполнения была передача по ссылке, которая стала устаревшей). Итак, вы должны использовать оператор clone в PHP5 для копирования объектов:

$objectB = clone $objectA;

Также обратите внимание, что по ссылке передаются только объекты, а не другие переменные. Следующее может прояснить ситуацию:

4
ответ дан 30 November 2019 в 06:25
поделиться
Другие вопросы по тегам:

Похожие вопросы: