Что такое клонирование объектов в php? - PullRequest
36 голосов
/ 27 января 2010

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

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

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

Ответы [ 5 ]

38 голосов
/ 27 января 2010

Клонирование объекта - это процесс создания копии объекта. Как указывало Коди , клонирование в 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() в Address. В противном случае вы получите головную боль, пытаясь выяснить, почему ваши данные облажались.

25 голосов
/ 27 января 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"
}
7 голосов
/ 27 января 2010

Объектное клонирование, с точки зрения PHP 5, это то, что известно как «мелкая копия» . Затем он вызывает метод __clone () для клонируемого объекта.

5 голосов
/ 22 мая 2012

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

function deepClone($object)
{
    return unserialize(serialize($object));
}
1 голос
/ 04 июня 2014

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

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

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

...