Когда я перехожу к руководству PHP (http://php.net/manual/en/language.oop5.basic.php), я наткнулся на следующую путаницу:
При назначении уже созданного экземпляра класса новой переменной новая переменная будет обращаться к тому же экземпляру, что и назначенный объект.
И ниже руководство содержит следующий пример:
<?php
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$instance->var = '$assigned will have this value';
$instance = null; // $instance and $reference become null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
С выходом
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned will have this value"
}
Не должен быть 3-й случай также NULL, если
новая переменная будет обращаться к тому же экземпляру, что и объект, который был назначен
В противном случае представляется, что присваиваемый $ передается по значению, а не ссылку, если первый инициатор ($ instance) был установлен в NULL, а присвоенный $ не изменил его значение.
Первый :-
Схема подсчета ссылок пользователей PHP для сбора мусора означает, что каждый раз, когда вы назначаете объектную переменную другому, вы увеличиваете этот счетчик на 1 и каждый раз, когда переменная выходит за пределы области действия, счетчик будет уменьшаться на 1
Второе: - (передача переменных по refrence)
$ a = 5; //рассмотрим адрес памяти $ a 25 или мы можем сказать, что "$ a" - это указатель, указывающий на местоположение 25, поэтому каждый раз, когда мы назначаем что-то в нем или проверяем его другим, мы получаем значение расположение этой переменной,
такой же как
$ b = 10; //может быть внутренним адресом памяти 26
но важно то, что:
$ a = 10; //адрес памяти 25 $ b = & $ a; // Адрес памяти $ b также 25
поэтому, если я напишу $ a = 11; поэтому значение $ b также изменится, поскольку они являются именем того же места в памяти, поэтому, когда я меняю его, это влияет и на других,
Теперь поговорим об этой проблеме: -
$instance = new SimpleClass();
здесь объект создается в памяти, мы можем называть его "x" по адресу "x_address", а переменная также создает имя $ instance, где "instance_address" - это местоположение "x_adderss" и таблица "Refrence" выглядят следующим образом:
RefrenceTable: -
object | refrence_count | memory_address
| |
'x' | 1 | 'x_address'
и Variable stack выглядят следующим образом:
Стек: -
Variable_name | Variable_address | Variable_value
| |
instance | 'instance_address' | 'x_address'
Теперь следующее утверждение
$assigned = $instance;
Переменный стек: -
Variable_name | Variable_address | Variable_value
| |
instance | 'instance_address' | 'x_address'
assigned | 'assigned_address' | 'x_address'
а также
RefrenceTable: -
object | refrence_count | memory_address
| |
'x' | 2 | 'x_address'
Потому что теперь 2 varialbe refrencing этого объекта, поэтому этот объект будет только мусором, когда оба будут выходить за рамки
Следующий оператор
$reference = & $instance; // One of the most important line
Переменный стек: -
Variable_name | Variable_address | Variable_value
| |
instance | 'instance_address' | 'x_address'
assigned | 'assigned_address' | 'x_address'
refrence | 'instance_address' | 'x_address' // because pointing the same
// memory as instance
RefrenceTable: -
object | refrence_count | memory_address
| |
'x' | 2 | 'x_address'
Заметьте, что refrence _count не увеличился, потому что этот varialbe указывает на какое-то место. Другими словами, мы можем сказать, что теперь мы можем указать местоположение → 'instance_address' с двумя именами
Следующее выражение:
$instance->var = '$assigned will have this value'; // Not so some changed happend in 'x_address'
Следующее выражение:
$instance = null; // one
важной линии
Переменный стек: -
Variable_name | Variable_address | Variable_value
| |
instance | 'instance_address' | NULL
assigned | 'assigned_address' | 'x_address'
refrence | 'instance_address' | NULL // because pointing the same
// memory as instance
Because instance and refrenced point to same location, if we change one values second will automaticallye changed, so both become null
Но refrence_count объекта 'x' будет уменьшаться на 1
RefrenceTable: -
object | refrence_count | memory_address
| |
'x' | 1 | 'x_address'
поэтому $ присваивает все еще объект объекту в памяти,
и когда мы напишем вот так:
$assigned = null;
затем
Variable_name | Variable_address | Variable_value
| |
instance | 'instance_address' | NULL
assigned | 'assigned_address' | NULL
refrence | 'instance_address' | NULL // because pointing the same
// memory as instance
object | refrence_count | memory_address
| |
'x' | 0 | 'x_address' // Marked for Garbe collection
Спасибо :) {Извините за слабый английский, им не родной английский оратор}
UPDATE: изменил диаграмму и объяснение, чтобы более точно отразить то, что происходит под капотом.
В компьютерных языках переменные называются ячейками памяти, которые используются для хранения значений. На скомпилированных языках имена переменных обычно исчезают во время компиляции; они просто помогают языкам для программистов. Интерпретированные языки сохраняют имена переменных, поскольку они нуждаются в них во время выполнения.
PHP хранит значения простых типов (bool, integer, float, string) в переменных; он имеет другой способ хранения объектов: отдельный блок памяти выделяется для хранения данных объекта, а переменная содержит ссылку/указатель на данные объекта (адрес в памяти, где хранятся данные объекта).
Назначение объекта не дублирует данные объекта; он просто копирует адрес данных в новую переменную. Чтобы дублировать данные объекта, нужно использовать оператор clone
следующим образом: $duplicate = clone $instance;
Код:
$instance = new SimpleClass();
$assigned = $instance;
$reference =& $instance;
$duplicate = clone $instance;
$number = 123;
производит что-то подобное в памяти:
$instance
$reference
+----------------------+ +----------------------------+
| address of object #1 | --------> | SimpleClass object #1 data |
+----------------------+ +----------------------------+
^
$assigned |
+----------------------+ |
| address of object #1 | ------------------------+
+----------------------+
$duplicate
+----------------------+ +----------------------------+
| address of object #2 | --------> | SimpleClass object #2 data |
+----------------------+ +----------------------------+
$number
+------+
| 123 |
+------+
Прямоугольники - это ячейки памяти, используемые для хранения данных; некоторые из них имеют над ними имена (переменные), другие - нет (блоки памяти, которые хранят данные объектов).
Как это работает:
$instance = new SimpleClass();
выделить блок памяти для хранения нового объекта типа SimpleClass
и сохранить ссылку на него (его адрес памяти) в переменной $instance
;$assigned = $instance;
копирует значение, хранящееся в переменной $instance
(т.е. ссылку на объект) в новую переменную $assigned
; это означает $assigned
точки одному и тому же объекту типа SimpleClass
как $instance
; доступ к свойствам объекта с помощью $instance->var
или $assigned->var
- это то же самое, потому что они оба указывают на один и тот же экземпляр типа SimpleClass
;$reference = & $instance;
добавляет новое имя ($reference
) в ячейку памяти (переменную), идентифицированную именем $instance
;$duplicate = clone $instance;
аналогичен $instance = new SimpleClass();
но вновь созданный объект не инициализируется вызовом его конструктора; вместо этого данные объекта, на который ссылается $instance
, копируются в новый объект, тогда его метод __clone()
вызывается, если существует;$instance = NULL;
заменит содержимое переменной $instance
на NULL
(перестает указывать на объект SimpleClass
# 1), но это не повлияет ни на $assigned
SimpleClass
(это другая переменная), ни на объект SimpleClass
# 1; к объекту все еще можно получить доступ через переменную $assigned
; $reference
будет иметь то же значение, что и $instance
потому что это просто имена для одного и того же местоположения памяти (теперь он хранит NULL
).Структуры данных теперь выглядят так:
$instance
$reference
+-------------------+ +----------------------------+
| NULL | | SimpleClass object #1 data |
+-------------------+ +----------------------------+
^
$assigned |
+----------------------+ |
| address of object #1 | ------------------------+
+----------------------+
$duplicate
+----------------------+ +----------------------------+
| address of object #2 | --------> | SimpleClass object #2 data |
+----------------------+ +----------------------------+
$number
+------+
| 123 |
+------+
unset($instance);
с unset($instance);
просто удаляет имя $instance
из переменной; потому что у него все еще есть другое имя ($reference
), переменная все еще существует, и ее можно получить и изменить, используя другое имя. Когда $reference
также отключается, переменная больше не может быть доступна, и используемая память будет выпущена в следующем цикле сбора мусора. То же самое происходит, когда $assigned
не установлен (как переменная, так и данные объекта становятся недоступными, и они будут выпущены).
$reference -> $instance
не совсем корректно. И $reference
и $instance
являются псевдонимами для одного и того же значения в таблице символов. Ни один из них не относится к другому, они просто относятся к одному значению. Согласно вашему объяснению, это не должно работать: 3v4l.org/5gaCE
zval
s, указатели C и т. Д., И это усложнит понимание объяснения.
Переменная, содержащая объект, фактически содержит ссылку на объект. Подумайте о каждом экземпляре объекта как о жизни в каком-то пуле объектов где-то за кулисами, а переменная просто держит что-то вроде "объекта № 3", ссылку на объект.
Если вы присвойте эту ссылку объекту другой переменной через =
, будет сделана копия этой ссылки. Теперь две переменные содержат копию "объекта № 3", которая, очевидно, относится к одному и тому же объекту.
Присвоение по ссылке с помощью =&
означает, что две переменные указывают на одну и ту же ссылку, поэтому любое изменение этой ссылки (например, ее перезапись с null
) повлияет на обе переменные. Объект все еще продолжает существовать за кулисами, хотя другая переменная, содержащая другую ссылку на нее, не затрагивается.