PHP Class - присвоение инициируемого класса новой переменной

0

Когда я перехожу к руководству 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, а присвоенный $ не изменил его значение.

  • 2
    Все, что вы делаете, это устанавливаете $ экземпляры «указатели» и $ reference на null, не удаляя реальный объект (пока на него все еще ссылаются другие переменные), поэтому назначенный «указатель» $ все еще указывает на экземпляр объекта в Память
  • 0
    Объекты всегда обрабатываются как «по ссылке» и определенно не «по значению», хотя на самом деле они являются указателем, а не ссылкой
Показать ещё 4 комментария
Теги:
class
oop

3 ответа

0
Лучший ответ

Первый :-

Схема подсчета ссылок пользователей 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

Спасибо :) {Извините за слабый английский, им не родной английский оратор}

0

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 не установлен (как переменная, так и данные объекта становятся недоступными, и они будут выпущены).

  • 0
    Ваше объяснение $reference -> $instance не совсем корректно. И $reference и $instance являются псевдонимами для одного и того же значения в таблице символов. Ни один из них не относится к другому, они просто относятся к одному значению. Согласно вашему объяснению, это не должно работать: 3v4l.org/5gaCE
  • 0
    Я не копался в коде PHP, я точно не знаю, как они представлены в памяти. Я попытался дать объяснение логике кода. Добавление таблицы символов в обсуждение также перетянет много других деталей реализации, таких как zval s, указатели C и т. Д., И это усложнит понимание объяснения.
Показать ещё 3 комментария
0

Переменная, содержащая объект, фактически содержит ссылку на объект. Подумайте о каждом экземпляре объекта как о жизни в каком-то пуле объектов где-то за кулисами, а переменная просто держит что-то вроде "объекта № 3", ссылку на объект.

Если вы присвойте эту ссылку объекту другой переменной через =, будет сделана копия этой ссылки. Теперь две переменные содержат копию "объекта № 3", которая, очевидно, относится к одному и тому же объекту.
Присвоение по ссылке с помощью =& означает, что две переменные указывают на одну и ту же ссылку, поэтому любое изменение этой ссылки (например, ее перезапись с null) повлияет на обе переменные. Объект все еще продолжает существовать за кулисами, хотя другая переменная, содержащая другую ссылку на нее, не затрагивается.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню