Existe-t-il une fonction pour faire une copie d'un tableau PHP vers un autre?
530
Existe-t-il une fonction pour faire une copie d'un tableau PHP vers un autre?
J'ai été brûlé plusieurs fois en essayant de copier des tableaux PHP. Je veux copier un tableau défini à l'intérieur d'un objet vers un global à l'extérieur.
Vous pourriez être confus par des subtilités telles que ArrayObject, qui est un objet qui agit exactement comme un tableau. Cependant, étant un objet, il a une sémantique de référence.
Edit: @AndrewLarsson soulève un point dans les commentaires ci-dessous. PHP a une fonctionnalité spéciale appelée "références". Ils sont quelque peu similaires aux pointeurs dans des langages comme C / C ++, mais pas tout à fait les mêmes. Si votre tableau contient des références, alors que le tableau lui-même est transmis par copie, les références seront toujours résolues vers la cible d'origine. C'est bien sûr généralement le comportement souhaité, mais j'ai pensé qu'il valait la peine d'être mentionné.
Vous n'avez pas répondu à la question. Vous avez seulement expliqué le problème. Ce qui, pour l'OP, est très probablement ce qu'il cherchait. Cependant, pour moi (et d'autres aussi), venant ici près de quatre ans plus tard avec un problème similaire, je n'ai toujours pas de bon moyen de cloner un tableau sans modifier le tableau d'origine (qui inclut également des pointeurs internes). Je suppose qu'il est temps pour moi de poser ma propre question.
Andrew Larsson
28
@AndrewLarsson Mais PHP le fait par défaut - c'est l'essentiel. Les références ne sont pas résolues cependant, donc si vous en avez besoin, vous devrez parcourir récursivement le tableau et en créer un nouveau - De même, si le tableau source contient des objets et que vous souhaitez les cloner, vous devrez le faire manuellement. Gardez également à l'esprit que les références en PHP ne sont pas les mêmes que les pointeurs en C. Sans rien savoir de votre cas, puis-je suggérer qu'il est étrange d'avoir un tableau de références dans le premier cas, surtout si vous n'avez pas l'intention de traiter les comme références? Quel est le cas d'utilisation?
Mais qu'en est-il quand ce n'est pas un comportement souhaité? La question demande comment faire une profonde copie. Ce n'est évidemment pas souhaité. Votre réponse est pas mieux que: $copy = $original;. Ce qui ne fonctionne pas si les éléments du tableau sont des références.
doug65536
8
Comme toujours, phpnous présente le résultat le moins attendu , car cette solution ne fonctionne pas toujours . $a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];imprime array0pendant les $a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];impressions array1. Apparemment, certains tableaux sont copiés par référence.
Tino
186
PHP copiera le tableau par défaut. Les références en PHP doivent être explicites.
$a = array(1,2);
$b = $a;// $b will be a different array
$c =&$a;// $c will be a reference to $a
L'utilisation de la référence peut être importante si le tableau est énorme. Je ne suis pas sûr, mais je suppose que cela devrait entraîner une consommation de mémoire inférieure et de meilleures performances (pas besoin de copier l'ensemble du tableau en mémoire).
robsch
11
@robsch - au niveau de la logique du programme, le tableau est copié. Mais en mémoire, il ne sera pas copié tant qu'il ne sera pas modifié - car PHP utilise la sémantique de copie sur écriture pour tous les types. stackoverflow.com/questions/11074970/…
Jessica Knight
@CoreyKnight Bon à savoir. Merci pour ça.
robsch
4
notez que ce n'est pas vrai pour les tableaux imbriqués, ce sont des références et donc vous vous retrouvez avec un désordre cassé
MightyPork
45
Si vous avez un tableau qui contient des objets, vous devez faire une copie de ce tableau sans toucher son pointeur interne, et vous avez besoin de tous les objets à cloner (afin de ne pas modifier les originaux lorsque vous apportez des modifications au copié tableau), utilisez-le.
L'astuce pour ne pas toucher le pointeur interne du tableau est de vous assurer que vous travaillez avec une copie du tableau, et non avec le tableau d'origine (ou une référence à celui-ci), donc l'utilisation d'un paramètre de fonction fera le travail (donc, c'est une fonction qui prend un tableau).
Notez que vous devrez toujours implémenter __clone () sur vos objets si vous souhaitez que leurs propriétés soient également clonées.
Cette fonction fonctionne pour tout type de tableau (y compris les types mixtes).
function array_clone($array){return array_map(function($element){return((is_array($element))? array_clone($element):((is_object($element))? clone $element
: $element
));}, $array);}
Gardez à l'esprit qu'il s'agit d'un cas particulier. Notez également que cela ne clonera que les références de premier niveau. Si vous avez un tableau profond, vous ne clonerez pas les nœuds plus profonds, s'ils sont des références. Cela pourrait ne pas être un problème dans votre cas, mais gardez-le à l'esprit.
troelskn
4
@troelskn Je l'ai corrigé en ajoutant une récursivité. Cette fonction fonctionnerait désormais sur n'importe quel type de tableau, y compris les types mixtes. Il fonctionne également aussi bien pour les tableaux simples, il n'est donc plus localisé. Il s'agit essentiellement d'une machine de clonage de baie universelle. Vous auriez encore besoin de définir la fonction __clone () dans vos objets s'ils sont profonds, mais cela dépasse la "portée" de cette fonction (désolé pour le mauvais jeu de mots).
Andrew Larsson
2
Je crois fermement que c'est la vraie réponse à cette question, la seule façon que j'ai vue de copier en profondeur un tableau contenant des objets.
Patrick
Il n'itère pas les propriétés des objets qui peuvent avoir d'autres tableaux et objets référencés.
ya.teck
6
Cette utilisation de __FUNCTION__est géniale.
zessx
29
Quand tu fais
$array_x = $array_y;
PHP copie le tableau, donc je ne sais pas comment vous vous seriez brûlé. Pour votre cas,
global $foo;
$foo = $obj->bar;
devrait bien fonctionner.
Pour être brûlé, je pense que vous auriez dû utiliser des références ou vous attendre à ce que les objets à l'intérieur des tableaux soient clonés.
oui, mais les clés seront modifiées, citation: Les valeurs dans le tableau d'entrée avec les touches numériques seront renumérotées avec des clés d'incrémentation à partir de zéro dans le tableau de résultats.
En général, cela fonctionne bien, mais dans certains cas, il peut lever une exception car toutes les variables ne sont pas sérialisables (par exemple les fermetures et les connexions à la base de données).
ya.teck
Une autre chose à noter est que les références aux objets peuvent être restaurées si une classe implémente la méthode magique __wakeup.
ya.teck
Merci, enfin quelque chose qui fonctionne vraiment, pas les autres réponses de bollock ayant beaucoup de votes positifs, ils n'ont sûrement pas traité le tableau d'objets comme spécifié en question où le nombre d'éléments dans le tableau peut changer, mais certainement pas les références à la objets à l'intérieur
// 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"}
Qu'en est-il array_slice($arr, 0)ou quand vous ne vous souciez pas des clés array_values($arr),? Je pense qu'ils pourraient être plus rapides que de rechercher dans un tableau. En outre, en javascript, il est très populaire d'utiliser Array.slice()pour cloner des tableaux.
Christian
Dans JS, nous avons Object pour les paires clé-valeur et Array . PHP ne fait pas cette différence. Pour les tableaux PHP avec des index numérotés, array_sliceet toutes les autres méthodes mentionnées ici fonctionnent très bien. Mais si vous souhaitez fusionner plusieurs paires clé-valeur (comme cela est également possible avec JS-Objects via Object.assignou la syntaxe étalée ), cela array_replacepeut être plus utile.
Putzi San
@Christian merci pour la suggestion array_values()qui a parfaitement fonctionné pour mon cas d'utilisation.
bigsee
11
Si vous n'avez que des types de base dans votre tableau, vous pouvez le faire:
$copy = json_decode( json_encode($array),true);
Vous n'aurez pas besoin de mettre à jour les références manuellement
Je sais que cela ne fonctionnera pas pour tout le monde, mais cela a fonctionné pour moi
+1 c'est vraiment une mauvaise chose à faire, mais c'est techniquement correct et intelligent. Si je voyais cela dans le code, je ferais face à Palm mais je ne peux pas m'empêcher de l'aimer.
Reactgular
4
Comme cela n'a été couvert dans aucune des réponses et est maintenant disponible en PHP 5.3 (en supposant que Original Post utilisait 5.2).
Afin de maintenir une structure de tableau et de changer ses valeurs, je préfère utiliser array_replaceou en array_replace_recursivefonction de mon cas d'utilisation.
Voici un exemple d'utilisation array_replaceet de array_replace_recursivedémonstration de sa capacité à maintenir l'ordre indexé et à supprimer une référence.
Fonctionne sur les tableaux indexés et indexés par nom
$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);?>
Dans le tableau php, vous devez simplement les affecter à une autre variable pour obtenir une copie de ce tableau. Mais vous devez d'abord vous assurer de son type, qu'il s'agisse de array, arrayObject ou stdObject.
Réponses:
En PHP, les tableaux sont attribués par copie, tandis que les objets sont attribués par référence. Cela signifie que:
Donnera:
Tandis que:
Rendements:
Vous pourriez être confus par des subtilités telles que
ArrayObject
, qui est un objet qui agit exactement comme un tableau. Cependant, étant un objet, il a une sémantique de référence.Edit: @AndrewLarsson soulève un point dans les commentaires ci-dessous. PHP a une fonctionnalité spéciale appelée "références". Ils sont quelque peu similaires aux pointeurs dans des langages comme C / C ++, mais pas tout à fait les mêmes. Si votre tableau contient des références, alors que le tableau lui-même est transmis par copie, les références seront toujours résolues vers la cible d'origine. C'est bien sûr généralement le comportement souhaité, mais j'ai pensé qu'il valait la peine d'être mentionné.
la source
$copy = $original;
. Ce qui ne fonctionne pas si les éléments du tableau sont des références.php
nous présente le résultat le moins attendu , car cette solution ne fonctionne pas toujours .$a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];
imprimearray0
pendant les$a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];
impressionsarray1
. Apparemment, certains tableaux sont copiés par référence.PHP copiera le tableau par défaut. Les références en PHP doivent être explicites.
la source
Si vous avez un tableau qui contient des objets, vous devez faire une copie de ce tableau sans toucher son pointeur interne, et vous avez besoin de tous les objets à cloner (afin de ne pas modifier les originaux lorsque vous apportez des modifications au copié tableau), utilisez-le.
L'astuce pour ne pas toucher le pointeur interne du tableau est de vous assurer que vous travaillez avec une copie du tableau, et non avec le tableau d'origine (ou une référence à celui-ci), donc l'utilisation d'un paramètre de fonction fera le travail (donc, c'est une fonction qui prend un tableau).
Notez que vous devrez toujours implémenter __clone () sur vos objets si vous souhaitez que leurs propriétés soient également clonées.
Cette fonction fonctionne pour tout type de tableau (y compris les types mixtes).
la source
__FUNCTION__
est géniale.Quand tu fais
PHP copie le tableau, donc je ne sais pas comment vous vous seriez brûlé. Pour votre cas,
devrait bien fonctionner.
Pour être brûlé, je pense que vous auriez dû utiliser des références ou vous attendre à ce que les objets à l'intérieur des tableaux soient clonés.
la source
array_merge()
est une fonction dans laquelle vous pouvez copier un tableau dans un autre en PHP.la source
$a_c = array_combine(array_keys($a), array_values($a))
.simple et rend la copie profonde brisant tous les liens
la source
J'aime
array_replace
(ouarray_replace_recursive
).$cloned = array_replace([], $YOUR_ARRAY);
Cela fonctionne comme à
Object.assign
partir de JavaScript.aura pour résultat
la source
array_slice($arr, 0)
ou quand vous ne vous souciez pas des clésarray_values($arr)
,? Je pense qu'ils pourraient être plus rapides que de rechercher dans un tableau. En outre, en javascript, il est très populaire d'utiliserArray.slice()
pour cloner des tableaux.array_slice
et toutes les autres méthodes mentionnées ici fonctionnent très bien. Mais si vous souhaitez fusionner plusieurs paires clé-valeur (comme cela est également possible avec JS-Objects viaObject.assign
ou la syntaxe étalée ), celaarray_replace
peut être plus utile.array_values()
qui a parfaitement fonctionné pour mon cas d'utilisation.Si vous n'avez que des types de base dans votre tableau, vous pouvez le faire:
Vous n'aurez pas besoin de mettre à jour les références manuellement
Je sais que cela ne fonctionnera pas pour tout le monde, mais cela a fonctionné pour moi
la source
Comme cela n'a été couvert dans aucune des réponses et est maintenant disponible en PHP 5.3 (en supposant que Original Post utilisait 5.2).
Afin de maintenir une structure de tableau et de changer ses valeurs, je préfère utiliser
array_replace
ou enarray_replace_recursive
fonction de mon cas d'utilisation.http://php.net/manual/en/function.array-replace.php
Voici un exemple d'utilisation
array_replace
et dearray_replace_recursive
démonstration de sa capacité à maintenir l'ordre indexé et à supprimer une référence.http://ideone.com/SzlBUZ
Le code ci-dessous est écrit en utilisant la syntaxe de tableau court disponible depuis PHP 5.4 qui remplace
array()
par[]
. http://php.net/manual/en/language.types.array.phpFonctionne sur les tableaux indexés et indexés par nom
Production:
la source
Je le sais depuis longtemps, mais cela a fonctionné pour moi ..
la source
Voici comment je copie mes tableaux en Php:
Cela produit:
la source
$test2 = $test;
? Quel problèmeArrayObject
résout ici?la source
Le moyen le plus sûr et le moins cher que j'ai trouvé est:
Cela a également l'avantage de réindexer le tableau.
Cela ne fonctionnera pas comme prévu sur le tableau associatif (hachage), mais pas la plupart des réponses précédentes.
la source
Crée une copie de l'ArrayObject
depuis https://www.php.net/manual/en/arrayobject.getarraycopy.php
la source
Définissez ceci:
Copiez $ _ARRAY dans $ _ARRAY2:
la source
Dans le tableau php, vous devez simplement les affecter à une autre variable pour obtenir une copie de ce tableau. Mais vous devez d'abord vous assurer de son type, qu'il s'agisse de array, arrayObject ou stdObject.
Pour un tableau php simple:
la source
la source
$arr_one_copy = array_combine(array_keys($arr_one), $arr_one);
Juste pour poster une autre solution;)
la source
Préserve à la fois la clé et les valeurs. Le tableau «a» est une copie exacte du tableau «b»
la source