что такое клонирование объектов в php?

Может кто-нибудь объяснить мне

  • что такое клонирование объектов в php?

  • Когда я должен использовать ключевое слово clone в php?


person Community    schedule 27.01.2010    source источник


Ответы (5)


Клонирование объекта — это процесс создания копии объекта. Как указал Cody, клонирование в 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 с внутренним адресом объекта.

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 объектов User, но вы хотите иметь возможность предоставить им копию объекта Address. Приведенный выше пример иллюстрирует это. Метод getAddress возвращает вызывающим объектам клон объекта адреса. Это означает, что если вызывающий объект изменит объект Address, внутренний адрес пользователя не изменится. Если вы не предоставили клон, то внешний объект смог бы изменить внутренний адрес пользователя, потому что по умолчанию дается ссылка, а не клон.

Надеюсь, все это имеет какой-то смысл.

PS.
Имейте в виду, однако, что если Address также будет иметь внутренние объекты, вам нужно будет убедиться, что Address делает глубокую копию себя при клонировании (согласно моему второму примеру этого поста). ), определив __clone() в Address. В противном случае вы получите головную боль, пытаясь понять, почему ваши данные облажались.

person Decent Dabbler    schedule 27.01.2010

Клонирование используется для создания подлинной копии объекта. Присвоение объекта другой переменной не создает копию, а создает ссылку на ту же ячейку памяти, что и объект:

<?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"
}
person leepowers    schedule 27.01.2010
comment
Но зачем клонировать его вместо того, чтобы делать $o2= new stdClass;, изменение свойств, таких как $o2->a= 'd';, дает тот же результат, верно? - person samayo; 27.01.2014
comment
@samayo: Нет, это также $o3->b = $o->b. Имейте в виду, что leepowers написал простой пример, но преимущество того же типа объекта со всеми скопированными свойствами, которые впоследствии можно переназначить без изменения исходного объекта, огромно в более сложных сценариях. - person Samuel Kirschner; 23.02.2017

Клонирование объектов в PHP 5 называется "мелкой копией". . Затем он вызывает метод __clone() для клонируемого объекта.

person Cody Haines    schedule 27.01.2010

Если вам нужен глубокий клон, то есть клоны дочерних объектов и клоны внучатых объектов, вы можете либо перезаписать __clone в каждом из классов, либо просто сериализовать+несериализовать объект:

function deepClone($object)
{
    return unserialize(serialize($object));
}
person cweiske    schedule 22.05.2012
comment
Это отличный обходной путь. Вы экономите мне часы кодирования, спасибо! - person Salvi Pascual; 24.01.2020

Как объяснялось в других ответах, clone создает неглубокую копию объекта.

Если вам нужно сделать глубокую копию (т. е. рекурсивную копию), вы можете перегрузить методы __clone().

Вы также можете использовать эту библиотеку: MyCLabs\DeepCopy, которая более проста и мощнее простого клона.

person Matthieu Napoli    schedule 04.06.2014