Есть ли функция, чтобы сделать копию массива PHP в другой? - PullRequest
478 голосов
/ 07 октября 2009

Есть ли функция для копирования массива PHP в другой?

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

Ответы [ 18 ]

863 голосов
/ 07 октября 2009

В PHP массивы назначаются путем копирования, а объекты - по ссылке. Это означает, что:

$a = array();
$b = $a;
$b['foo'] = 42;
var_dump($a);

даст:

array(0) {
}

Принимая во внимание:

$a = new StdClass();
$b = $a;
$b->foo = 42;
var_dump($a);

Урожайность:

object(stdClass)#1 (1) {
  ["foo"]=>
  int(42)
}

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

Редактировать: @AndrewLarsson поднимает вопрос в комментариях ниже. PHP имеет специальную функцию под названием «ссылки». Они несколько похожи на указатели в таких языках, как C / C ++, но не совсем так. Если ваш массив содержит ссылки, то, хотя сам массив передается копией, ссылки все равно будут преобразовываться в исходную цель. Это, конечно, обычно желаемое поведение, но я подумал, что стоит упомянуть.

170 голосов
/ 07 октября 2009

PHP скопирует массив по умолчанию. Ссылки в PHP должны быть явными.

$a = array(1,2);
$b = $a; // $b will be a different array
$c = &$a; // $c will be a reference to $a
39 голосов
/ 18 июля 2013

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

Хитрость в том, чтобы не трогать внутренний указатель массива, - убедиться, что вы работаете с копией массива, а не с исходным массивом (или ссылкой на него), поэтому использование параметра функции позволит выполнить работу (таким образом, это функция, которая принимает массив).

Обратите внимание, что вам все равно нужно будет реализовать __ clone () на ваших объектах, если вы хотите, чтобы их свойства также были клонированы.

Эта функция работает для любого типа массива (включая смешанный тип).

function array_clone($array) {
    return array_map(function($element) {
        return ((is_array($element))
            ? array_clone($element)
            : ((is_object($element))
                ? clone $element
                : $element
            )
        );
    }, $array);
}
28 голосов
/ 07 октября 2009

Когда вы делаете

$array_x = $array_y;

PHP копирует массив, поэтому я не уверен, как бы вы сгорели. Для вашего случая

global $foo;
$foo = $obj->bar;

должно работать нормально.

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

17 голосов
/ 08 декабря 2012

array_merge() - это функция, в которой вы можете копировать один массив в другой в PHP.

13 голосов
/ 05 ноября 2016

просто и делает глубокое копирование, ломая все ссылки

$new=unserialize(serialize($old));
9 голосов
/ 13 марта 2016

Если у вас есть только базовые типы в вашем массиве, вы можете сделать это:

$copy = json_decode( json_encode($array), true);

Вам не нужно обновлять ссылки вручную.
Я знаю, что это не будет работать для всех, но у меня это сработало

9 голосов
/ 16 марта 2018

Мне нравится array_replace (или array_replace_recursive).

$cloned = array_replace([], $YOUR_ARRAY);

Он работает как Object.assign из JavaScript.

$original = [ 'foo' => 'bar', 'fiz' => 'baz' ];

$cloned = array_replace([], $original);
$clonedWithReassignment = array_replace([], $original, ['foo' => 'changed']);
$clonedWithNewValues = array_replace([], $original, ['add' => 'new']);

$original['new'] = 'val';

приведет к

// original: 
{"foo":"bar","fiz":"baz","new":"val"}
// cloned:   
{"foo":"bar","fiz":"baz"}
// cloned with reassignment:
{"foo":"changed","fiz":"baz"}
// cloned with new values:
{"foo":"bar","fiz":"baz","add":"new"}
4 голосов
/ 20 августа 2014

Поскольку это не было охвачено ни одним из ответов и теперь доступно в PHP 5.3 (предполагается, что Original Post использовал 5.2).

Для поддержания структуры массива и изменения его значений я предпочитаю использовать array_replace или array_replace_recursive в зависимости от моего варианта использования.

http://php.net/manual/en/function.array-replace.php

Вот пример использования array_replace и array_replace_recursive, демонстрирующий, что он способен поддерживать индексированный порядок и способен удалять ссылку.

http://ideone.com/SzlBUZ

Код ниже написан с использованием синтаксиса короткого массива, доступного начиная с PHP 5.4, который заменяет array() на []. http://php.net/manual/en/language.types.array.php

Работает с массивами с индексами смещения и именования

$o1 = new stdClass;
$a = 'd';
//This is the base array or the initial structure
$o1->ar1 = ['a', 'b', ['ca', 'cb']];
$o1->ar1[3] = & $a; //set 3rd offset to reference $a

//direct copy (not passed by reference)
$o1->ar2 = $o1->ar1; //alternatively array_replace($o1->ar1, []);
$o1->ar1[0] = 'z'; //set offset 0 of ar1 = z do not change ar2
$o1->ar1[3] = 'e'; //$a = e (changes value of 3rd offset to e in ar1 and ar2)

//copy and remove reference to 3rd offset of ar1 and change 2nd offset to a new array
$o1->ar3 = array_replace($o1->ar1, [2 => ['aa'], 3 => 'd']);

//maintain original array of the 2nd offset in ar1 and change the value at offset 0
//also remove reference of the 2nd offset
//note: offset 3 and 2 are transposed
$o1->ar4 = array_replace_recursive($o1->ar1, [3 => 'f', 2 => ['bb']]);

var_dump($o1);

Выход:

["ar1"]=>
  array(4) {
    [0]=>
    string(1) "z"
    [1]=>
    string(1) "b"
    [2]=>
    array(2) {
      [0]=>
      string(2) "ca"
      [1]=>
      string(2) "cb"
    }
    [3]=>
    &string(1) "e"
  }
  ["ar2"]=>
  array(4) {
    [0]=>
    string(1) "a"
    [1]=>
    string(1) "b"
    [2]=>
    array(2) {
      [0]=>
      string(2) "ca"
      [1]=>
      string(2) "cb"
    }
    [3]=>
    &string(1) "e"
  }
  ["ar3"]=>
  array(4) {
    [0]=>
    string(1) "z"
    [1]=>
    string(1) "b"
    [2]=>
    array(1) {
      [0]=>
      string(2) "aa"
    }
    [3]=>
    string(1) "d"
  }
  ["ar4"]=>
  array(4) {
    [0]=>
    string(1) "z"
    [1]=>
    string(1) "b"
    [2]=>
    array(2) {
      [0]=>
      string(2) "bb"
      [1]=>
      string(2) "cb"
    }
    [3]=>
    string(1) "f"
  }
3 голосов
/ 24 февраля 2015

Я знаю это как давно, но у меня это сработало ..

$copied_array = array_slice($original_array,0,count($original_array));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...