Что такое клонирование объектов в php?
Может кто-нибудь объяснить мне
Что такое клонирование объектов в php?
Когда я должен использовать ключевое слово clone в php?
5 ответов
Клонирование объекта - это создание копии объекта. Как указал Коди, клонирование в PHP выполняется путем создания мелкой копии объекта. Это означает, что внутренние объекты клонированного объекта не будут клонированы, если только вы явно не указали объекту клонировать и эти внутренние объекты, определив магический метод. __clone()
,
Если вы не используете __clone
метод, внутренние объекты нового объекта будут ссылками на те же объекты в памяти, что и внутренние объекты исходного объекта, который был клонирован.
Рассмотрим эти примеры:
// in this exampe the internal member $_internalObject of both objects
// reference the same instance of stdClass in memory.
class CloneableClass
{
private $_internalObject;
public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}
}
$classA = new CloneableClass();
$classB = clone $classA;
// in this exampe the internal member $_internalObject of both objects
// DON'T reference the same instance of stdClass in memory, but are inividual instances
class CloneableClass
{
private $_internalObject;
public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}
// on clone, make a deep copy of this object by cloning internal member;
public function __clone()
{
$this->_internalObject = clone $this->_internalObject;
}
}
$classA = new CloneableClass();
$classB = clone $classA;
Варианты использования для клонирования будут, например, случаем, когда вы не хотите, чтобы внешние объекты связывались с внутренним состоянием объекта.
Допустим, у вас есть класс User с внутренним объектом Address.
class Address
{
private $_street;
private $_streetIndex;
private $_city;
// etc...
public function __construct( $street, $streetIndex, $city /* etc.. */ )
{
/* assign to internal values */
}
}
class User
{
// will hold instance of Address
private $_address;
public function __construct()
{
$this->_address = new Address( 'somestreet', '1', 'somecity' /* etc */ );
}
public function getAddress()
{
return clone $this->_address;
}
}
Ради аргументов, скажем, вы не хотите, чтобы внешние объекты связывались с внутренним адресом объектов пользователя, но вы хотите иметь возможность дать им копию объекта Address. Приведенный выше пример иллюстрирует это. getAddress
Метод возвращает клон объекта адреса вызывающим объектам. Это означает, что если вызывающий объект изменяет объект адреса, внутренний адрес пользователя не изменится. Если вы не дали клон, то внешний объект сможет изменить внутренний адрес пользователя, потому что по умолчанию дается ссылка, а не клон.
Надеюсь, что все это имеет смысл.
PS.:
Имейте в виду, однако, что если у Address также есть внутренние объекты, вы должны убедиться, что Address делает полную копию себя при клонировании (согласно моему второму примеру этого поста), определяя __clone()
в адрес. В противном случае вы получите головную боль при попытке выяснить, почему ваши данные облажались.
Клонирование используется для создания подлинной копии объекта. Присвоение объекта другой переменной не создает копию - скорее, он создает ссылку на ту же область памяти, что и объект:
<?php
$o= new stdclass;
$o->a= 'b';
$o->b= 'c';
$o2= $o;
$o2->a= 'd';
var_dump($o);
var_dump($o2);
$o3= clone $o;
$o3->a= 'e';
var_dump($o);
var_dump($o3);
?>
Этот пример кода выведет следующее:
object(stdClass)#1 (2) {
["a"]=>
string(1) "d"
["b"]=>
string(1) "c"
}
object(stdClass)#1 (2) {
["a"]=>
string(1) "d"
["b"]=>
string(1) "c"
}
object(stdClass)#1 (2) {
["a"]=>
string(1) "d"
["b"]=>
string(1) "c"
}
object(stdClass)#2 (2) {
["a"]=>
string(1) "e"
["b"]=>
string(1) "c"
}
Клонирование объектов, с точки зрения PHP 5, называется "мелкой копией". Затем он вызывает метод __clone() для клонируемого объекта.
Если вам нужен глубокий клон, то есть клоны дочерних объектов и клоны объектов внука, вы можете либо перезаписать __clone
в каждом из классов или просто сериализовать + десериализовать объект:
function deepClone($object)
{
return unserialize(serialize($object));
}
Как объяснено в других ответах, clone
делает мелкую копию объекта.
Если вам нужно сделать глубокую копию (т.е. рекурсивную копию), вы можете перегрузить __clone()
методы.
Вы также можете использовать эту библиотеку: MyCLabs \ DeepCopy, которая является более простой и мощной, чем простой клон.