Подтвердить что ты не робот

Как клонировать массив объектов в PHP?

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

Есть ли простой способ клонирования массива, или я должен прокручивать его для клонирования каждого объекта?

4b9b3361

Ответ 1

Ссылки на те же объекты уже копируются при копировании массива. Но похоже, что вы хотите, чтобы мелкая копия глубоко копировала объекты, на которые ссылаются в первом массиве при создании второго массива, поэтому вы получаете два массива различных, но похожих объектов.

Самый интуитивный способ, который я могу придумать, - это цикл; там могут быть более простые или более элегантные решения:

$new = array();

foreach ($old as $k => $v) {
    $new[$k] = clone $v;
}

Ответ 2

$array = array_merge(array(), $myArray);

Ответ 3

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

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;
}

Ответ 4

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

$clone = array_map(function ($object) { return clone $object; }, $array);

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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, если вы этого не хотите.

Ответ 8

а также

$nuarr = json_decode(json_encode($array));

но это дорого, я предпочитаю версию Sebastien (array_map)

Ответ 9

Объекты передаются по указанию по умолчанию и не всегда легко клонировать, поскольку они могут иметь круглые ссылки. Вы бы лучше подошли с другим выбором структур данных.

Для тех, кто предоставляет решения для мелкой копии, проще:

 $b = (array)$a;

Для глубоких копий я не рекомендую это решение:

$nuarr = json_decode (json_encode ($ array));

Это для глубокой копии. Он поддерживает только подмножество типов PHP и будет обменивать объекты на массив или массивы на объекты, которые могут быть не такими, какие вы хотите, а также потенциально повреждаете двоичные значения и т.д.

Если вы сделаете ручную рекурсивную функцию для глубоких копий, использование памяти будет намного меньше для скалярных значений и ключей, поэтому использование json или любого сериализатора будет зависеть от его исполнения.

Лучше использовать unserialize (serialize ($ a)) для глубоких копий, если производительность не является проблемой, которая имеет более широкую поддержку для таких вещей, как объекты, хотя я не удивлюсь, если она сломается для круговых ссылок и нескольких других необычные вещи.

array_merge_recursive или array_walk_recursive также могут использоваться для массивов.

Вы можете легко создать свою собственную рекурсивную функцию, которая использует is_object и is_array для выбора соответствующих средств копирования.

Ответ 10

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

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

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

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

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

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

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