очень поздно, но в моей среде я проверил это (и это сработало): function arrayCopy (array $ a) {return $ a; } $ a1 = array (); for ($ i = 0; $ i <3; $ i ++) {$ a1 ["key- $ i"] = "value # $ i"; } $ a1 ["key-sub-array"] = array (1, 2, 3, 4); $ a2 = $ a1; $ a3 = arrayCopy ($ a1); for ($ i = 0; $ i <3; $ i ++) {if (! is_array ($ a2 ["key- $ i"])) {$ a2 ["key- $ i"] = "измененное значение # $ я"; }} $ a2 ["key-sub-array"] = array ("измененный подмассив 1", "измененный подмассив 2"); var_dump ($ a1); var_dump ($ a2); var_dump ($ a3); Хитрость заключается в том, чтобы не передавать массив в качестве ссылки в функцию ;-)
Свен
Ответы:
927
В PHP массивы назначаются путем копирования, а объекты - по ссылке. Это значит, что:
Вы можете запутаться в таких сложностях, как ArrayObject, например , объект, который действует точно так же, как массив. Однако, будучи объектом, он имеет ссылочную семантику.
Изменить: @AndrewLarsson поднимает вопрос в комментариях ниже. PHP имеет специальную функцию, называемую «ссылки». Они несколько похожи на указатели в таких языках, как C / C ++, но не совсем так. Если ваш массив содержит ссылки, то, хотя сам массив передается копией, ссылки все равно будут преобразовываться в исходную цель. Это, конечно, обычно желаемое поведение, но я подумал, что стоит упомянуть.
Вы не ответили на вопрос. Вы только объяснили проблему. Что для ОП, скорее всего, то, что он искал. Однако для меня (и других тоже), приехав сюда почти четыре года спустя с аналогичной проблемой, у меня все еще нет хорошего способа клонировать массив без изменения исходного массива (который также включает в себя внутренние указатели). Я полагаю, пришло время задать свой вопрос.
Эндрю Ларссон
28
@AndrewLarsson Но PHP делает это по умолчанию - в этом суть. Однако ссылки не разрешаются, поэтому, если вам это нужно, вам придется рекурсивно проходить по массиву и создавать новый - аналогично, если исходный массив содержит объекты и вы хотите, чтобы они были клонированы, вам придется делать это вручную. Помните также, что ссылки в PHP не совпадают с указателями в C. Не зная ничего о вашем случае, могу ли я предположить, что странно иметь массив ссылок в первом случае, особенно если вы не собираетесь рассматривать их как ссылки? Какой вариант использования?
Но как быть, когда это нежелательное поведение? Вопрос в том, как сделать глубокую копию. Это явно не желательно. Нет Ваш ответ не лучше: $copy = $original;. Что не работает, если элементы массива являются ссылками.
doug65536
8
Как всегда, phpдарит нам наименьший ожидаемый результат , потому что это решение не всегда работает . $a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];печатает array0пока $a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];печатает array1. Видимо, некоторые массивы скопированы по ссылке.
Тино
186
PHP будет копировать массив по умолчанию. Ссылки в PHP должны быть явными.
$a = array(1,2);
$b = $a;// $b will be a different array
$c =&$a;// $c will be a reference to $a
Использование ссылки может быть важно, если массив огромен. Я не уверен, но я предполагаю, что это должно привести к меньшему потреблению памяти и лучшей производительности (не нужно копировать весь массив в памяти).
robsch
11
@robsch - на уровне программной логики массив копируется. Но в памяти он фактически не будет скопирован, пока не будет изменен - потому что PHP использует семантику копирования при записи для всех типов. stackoverflow.com/questions/11074970/…
Джессика Найт
@CoreyKnight Полезно знать. Спасибо тебе за это.
Робш
4
обратите внимание, что это не верно для вложенных массивов, они являются ссылками, и поэтому вы заканчиваете с разбитым беспорядком
MightyPork
45
Если у вас есть массив, содержащий объекты, вам нужно сделать копию этого массива, не касаясь его внутреннего указателя, и вам необходимо клонировать все объекты (чтобы не изменять оригиналы при внесении изменений в скопированный объект). массив), используйте это.
Хитрость в том, чтобы не касаться внутреннего указателя массива, заключается в том, чтобы убедиться, что вы работаете с копией массива, а не с исходным массивом (или ссылкой на него), поэтому использование параметра функции позволит выполнить работу (таким образом, это функция, которая принимает массив).
Обратите внимание, что вам все равно нужно реализовать __clone () для ваших объектов, если вы хотите, чтобы их свойства также были клонированы.
Эта функция работает для любого типа массива (включая смешанный тип).
function array_clone($array){return array_map(function($element){return((is_array($element))? array_clone($element):((is_object($element))? clone $element
: $element
));}, $array);}
Имейте в виду, что это немного особый случай. Кроме того, обратите внимание, что это будет клонировать только ссылки первого уровня. Если у вас есть глубокий массив, вы не сможете клонировать более глубокие узлы, если они являются ссылками. Может не быть проблемой в вашем случае, но просто имейте это в виду.
troelskn
4
@troelskn Я исправил это, добавив некоторую рекурсию. Эта функция теперь будет работать с любым типом массива, включая смешанные типы. Это также работает для простых массивов, так что больше не локализуется. Это в основном универсальная машина для клонирования массивов. Вам все еще нужно определить функцию __clone () в ваших объектах, если они глубоки, но это выходит за рамки этой функции (извините за плохой каламбур).
Эндрю Ларссон
2
Я твердо верю, что это реальный ответ на этот вопрос. Единственный способ, которым я видел, - это глубокое копирование массива, содержащего объекты.
Патрик
Он не выполняет итерацию свойств объекта, которые могут иметь другие массивы и ссылочные объекты.
я.тек
6
Это использование __FUNCTION__великолепно.
zessx
29
Когда вы делаете
$array_x = $array_y;
PHP копирует массив, поэтому я не уверен, как бы вы сгорели. Для вашего случая
global $foo;
$foo = $obj->bar;
должно работать нормально.
Для того, чтобы сгореть, я думаю, вы должны были использовать ссылки или ожидать клонирования объектов внутри массивов.
да, но ключи будут изменены, цитата: Значения во входном массиве с цифровыми ключами будут перенумерованы с увеличивающимися ключами, начинающимися с нуля в результирующем массиве.
Обычно он работает нормально, однако в некоторых случаях он может генерировать исключение, потому что не все переменные являются сериализуемыми (например, замыкания и соединения с базой данных).
я.тек
Следует также отметить, что ссылки на объекты можно восстановить, если класс реализует магический метод __wakeup.
я.тек
Спасибо, наконец-то, что действительно работает, а не ответы на другие смелые ответы с большим количеством голосов, они, конечно, не имели дело с массивом объектов, как указано в вопросе, где может измениться количество элементов в массиве, но определенно не ссылки на объекты внутри них
// 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"}
Как насчет array_slice($arr, 0)или когда вам нет дела до ключей array_values($arr)? Я думаю, что они могут быть быстрее, чем поиск в массиве. Кроме того, в javascript он довольно популярен Array.slice()для клонирования массивов.
Кристиан
В JS у нас есть Object для пар ключ-значение и Array . PHP не делает эту разницу. Для массивов PHP с нумерованными индексами array_sliceи всех других методов, упомянутых здесь, работают очень хорошо. Но если вы хотите объединить несколько пар ключ-значение (как это также возможно с JS-Objects через Object.assignили с помощью синтаксиса распространения ), это array_replaceможет быть более полезным.
Putzi San
@ Кристиан, спасибо за предложение, array_values()которое отлично сработало для моего варианта использования.
Bigsee
11
Если у вас есть только базовые типы в вашем массиве, вы можете сделать это:
$copy = json_decode( json_encode($array),true);
Вам не нужно обновлять ссылки вручную,
я знаю, что это не будет работать для всех, но у меня это сработало
+1 это действительно плохая вещь, но технически правильная и умная. Если бы я видел это в коде, я столкнулся бы с пальмой, но я не могу не любить это.
Reactgular
4
Поскольку это не было охвачено ни одним из ответов и теперь доступно в PHP 5.3 (предполагается, что Original Post использовал 5.2).
Чтобы поддерживать структуру массива и изменять его значения, я предпочитаю использовать array_replaceили в array_replace_recursiveзависимости от моего варианта использования.
$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);
<?php
// Array of available fruits
$fruits = array("lemons"=>1,"oranges"=>4,"bananas"=>5,"apples"=>10);
$fruitsArrayObject =newArrayObject($fruits);
$fruitsArrayObject['pears']=4;// create a copy of the array
$copy = $fruitsArrayObject->getArrayCopy();
print_r($copy);?>
В массиве php вам нужно просто присвоить их другой переменной, чтобы получить копию этого массива. Но сначала вам нужно убедиться в его типе, будь то массив или arrayObject или stdObject.
Ответы:
В PHP массивы назначаются путем копирования, а объекты - по ссылке. Это значит, что:
Будет давать:
В то время как:
Урожайность:
Вы можете запутаться в таких сложностях, как
ArrayObject
, например , объект, который действует точно так же, как массив. Однако, будучи объектом, он имеет ссылочную семантику.Изменить: @AndrewLarsson поднимает вопрос в комментариях ниже. PHP имеет специальную функцию, называемую «ссылки». Они несколько похожи на указатели в таких языках, как C / C ++, но не совсем так. Если ваш массив содержит ссылки, то, хотя сам массив передается копией, ссылки все равно будут преобразовываться в исходную цель. Это, конечно, обычно желаемое поведение, но я подумал, что стоит упомянуть.
источник
$copy = $original;
. Что не работает, если элементы массива являются ссылками.php
дарит нам наименьший ожидаемый результат , потому что это решение не всегда работает .$a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];
печатаетarray0
пока$a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];
печатаетarray1
. Видимо, некоторые массивы скопированы по ссылке.PHP будет копировать массив по умолчанию. Ссылки в PHP должны быть явными.
источник
Если у вас есть массив, содержащий объекты, вам нужно сделать копию этого массива, не касаясь его внутреннего указателя, и вам необходимо клонировать все объекты (чтобы не изменять оригиналы при внесении изменений в скопированный объект). массив), используйте это.
Хитрость в том, чтобы не касаться внутреннего указателя массива, заключается в том, чтобы убедиться, что вы работаете с копией массива, а не с исходным массивом (или ссылкой на него), поэтому использование параметра функции позволит выполнить работу (таким образом, это функция, которая принимает массив).
Обратите внимание, что вам все равно нужно реализовать __clone () для ваших объектов, если вы хотите, чтобы их свойства также были клонированы.
Эта функция работает для любого типа массива (включая смешанный тип).
источник
__FUNCTION__
великолепно.Когда вы делаете
PHP копирует массив, поэтому я не уверен, как бы вы сгорели. Для вашего случая
должно работать нормально.
Для того, чтобы сгореть, я думаю, вы должны были использовать ссылки или ожидать клонирования объектов внутри массивов.
источник
array_merge()
это функция, в которой вы можете скопировать один массив в другой в PHP.источник
$a_c = array_combine(array_keys($a), array_values($a))
.простой и делает глубокое копирование, ломая все ссылки
источник
Мне нравится
array_replace
(илиarray_replace_recursive
).$cloned = array_replace([], $YOUR_ARRAY);
Это работает как
Object.assign
из JavaScript.приведет к
источник
array_slice($arr, 0)
или когда вам нет дела до ключейarray_values($arr)
? Я думаю, что они могут быть быстрее, чем поиск в массиве. Кроме того, в javascript он довольно популяренArray.slice()
для клонирования массивов.array_slice
и всех других методов, упомянутых здесь, работают очень хорошо. Но если вы хотите объединить несколько пар ключ-значение (как это также возможно с JS-Objects черезObject.assign
или с помощью синтаксиса распространения ), этоarray_replace
может быть более полезным.array_values()
которое отлично сработало для моего варианта использования.Если у вас есть только базовые типы в вашем массиве, вы можете сделать это:
Вам не нужно обновлять ссылки вручную,
я знаю, что это не будет работать для всех, но у меня это сработало
источник
Поскольку это не было охвачено ни одним из ответов и теперь доступно в 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Работает с массивами со смещением и именами
Вывод:
источник
Я знаю это как давно, но это сработало для меня ..
источник
Вот как я копирую свои массивы в Php:
Это выводит:
источник
$test2 = $test;
? Какую проблемуArrayObject
здесь решаем?источник
Самый безопасный и дешевый способ, который я нашел, это:
Это также дает преимущество для переиндексации массива.
Это не будет работать, как ожидается, для ассоциативного массива (хэш), но не для большинства предыдущих ответов.
источник
Создает копию ArrayObject
с https://www.php.net/manual/en/arrayobject.getarraycopy.php
источник
Определите это:
Скопируйте $ _ARRAY в $ _ARRAY2:
источник
В массиве php вам нужно просто присвоить их другой переменной, чтобы получить копию этого массива. Но сначала вам нужно убедиться в его типе, будь то массив или arrayObject или stdObject.
Для простого массива php:
источник
источник
$arr_one_copy = array_combine(array_keys($arr_one), $arr_one);
Просто чтобы опубликовать еще одно решение;)
источник
Сохраняет как ключ, так и значения. Массив 'a' является точной копией массива 'b'
источник