Как клонировать массив объектов в PHP? - PullRequest
54 голосов
/ 21 июня 2011

У меня есть массив объектов.Я знаю, что объекты присваиваются «ссылкой», а массивы - «значением».Но когда я присваиваю массив, каждый элемент массива ссылается на объект, поэтому, когда я изменяю объект в одном массиве, изменения отражаются в другом.или я должен пройти через него, чтобы клонировать каждый объект?

Ответы [ 12 ]

62 голосов
/ 17 июля 2012
$array = array_merge(array(), $myArray);
45 голосов
/ 21 июня 2011

Ссылки на те же объекты уже копируются при копировании массива.Но это звучит так, как будто вы хотите мелкое копирование глубокое копирование объектов, на которые имеются ссылки в первом массиве, при создании второго массива, поэтому вы получаете два массива различных, но похожих объектов.* Самый интуитивный способ, которым я могу придумать прямо сейчас, - это цикл;Там могут быть более простые или более элегантные решения:

$new = array();

foreach ($old as $k => $v) {
    $new[$k] = clone $v;
}
18 голосов
/ 21 июня 2011

Вам необходимо клонировать объекты, чтобы избежать ссылок на один и тот же объект.

function array_copy($arr) {
    $newArray = array();
    foreach($arr as $key => $value) {
        if(is_array($value)) $newArray[$key] = array_copy($value);
        else if(is_object($value)) $newArray[$key] = clone $value;
        else $newArray[$key] = $value;
    }
    return $newArray;
}
13 голосов
/ 31 октября 2013

Как рекомендует AndreKR, лучше использовать array_map (), если вы уже знаете, что ваш массив содержит объекты:

$clone = array_map(function ($object) { return clone $object; }, $array);
5 голосов
/ 21 июня 2011

Я также выбрал клон. Клонирование массива не работает (вы могли бы сделать это для некоторой реализации доступа к массиву), например, для клона массива с array_map :

class foo {
    public $store;
    public function __construct($store) {$this->store=$store;}
}

$f = new foo('moo');
$a = array($f);

$b = array_map(function($o) {return clone $o;}, $a);

$b[0]->store='bar';    
var_dump($a, $b);

Массив клонов с сериализацией и десериализацией

Если ваши объекты поддерживают сериализацию, вы можете даже отсортировать глубокое мелкое копирование / клон с переходом в их спящее состояние и обратно:

$f = new foo('moo');
$a = array($f);

$b = unserialize(serialize($a));

$b[0]->store='bar';
var_dump($a, $b);

Однако это может быть немного авантюрным.

2 голосов
/ 18 ноября 2016

Вот моя лучшая практика по массиву объектов и клонированию.Обычно хорошей идеей является наличие класса Collection для каждого класса объектов (или интерфейса), которые используются в массиве.С волшебной функцией __clone клонирование становится формализованной процедурой:

class Collection extends ArrayObject
{
     public function __clone()
     {
        foreach ($this as $key => $property) {
            $this[$key] = clone $property;
        }
     }
}

Чтобы клонировать ваш массив, используйте его как коллекцию, а затем клонируйте его:

$arrayObject = new Collection($myArray);
$clonedArrayObject = clone $arrayObject;

На шаг впередследует добавить метод клонирования в ваш класс и каждый подкласс тоже.Это важно для глубокого клонирования, или у вас могут быть непреднамеренные побочные эффекты:

class MyClass
{
     public function __clone()
     {
        $this->propertyContainingObject = clone $this->propertyContainingObject;
     }
}

Важное замечание по использованию ArrayObject заключается в том, что вы больше не можете использовать is_array().Так что учтите это при рефакторинге вашего кода.

2 голосов
/ 11 марта 2014

Я сделал это так:

function array_clone($array) {
    array_walk_recursive($array, function(&$value) {
        if(is_object($value)) {
            $value = clone $value;
        }
    });
    return $array;
}

Функция arg копирует массив без клонирования объектов, затем каждый вложенный объект клонируется. Поэтому он не будет работать, если алгоритм не используется внутри функции.

Обратите внимание, что эта функция рекурсивно клонирует массив. Вы можете использовать array_walk вместо array_walk_recursive, если не хотите, чтобы это произошло.

2 голосов
/ 21 июня 2011

Вам нужно зациклить его (возможно, для этого используется функция типа array_map()), нет функции PHP для автоматического выполнения глубокой копии массива.

0 голосов
/ 06 сентября 2018

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

$cloned = Arr::clone($array);

из этой библиотеки.

0 голосов
/ 23 мая 2018

Для PHP 5 и выше можно использовать ArrayObject cunstructur для клонирования массива, например:

$myArray = array(1, 2, 3);
$clonedArray = new ArrayObject($myArray);
...