616 votes

Existe-t-il une fonction permettant de faire une copie d'un tableau PHP vers un autre ?

Existe-t-il une fonction permettant de 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 de celui-ci.

0 votes

Vraiment en retard, mais dans mon environnement j'ai testé ceci (et ça a marché) : 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"] = "valeur modifiée #$i" ; } } $a2["key-sub-array"] = array("changed sub-array 1", "changed sub-array 2") ; var_dump($a1) ; var_dump($a2) ; var_dump($a3) ; L'astuce consiste à ne pas passer le tableau comme référence dans la fonction ;-)

1 votes

@Sven, y a-t-il une raison pour laquelle il s'agit d'un commentaire plutôt que d'une réponse ? Je n'arrive pas à comprendre.

1048voto

troelskn Points 51966

En PHP, les tableaux sont assignés par copie, alors que les objets sont assignés par référence. Cela signifie que :

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

Cédera :

array(0) {
}

Considérant que :

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

Rendement :

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

Vous pourriez être dérouté par des subtilités telles que ArrayObject qui est un objet qui se comporte exactement comme un tableau. Cependant, étant un objet, il possède une sémantique de référence.

Editer : @AndrewLarsson soulève un point dans les commentaires ci-dessous. PHP possède une fonctionnalité spéciale appelée "références". Elles sont un peu similaires aux pointeurs 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 passé par copie, les références seront toujours résolues vers la cible originale. Bien sûr, c'est généralement le comportement souhaité, mais j'ai pensé que cela valait la peine d'être mentionné.

137 votes

Vous n'avez pas répondu à la question. Vous avez seulement expliqué le problème. Ce qui, pour le PO, est très probablement ce qu'il recherchait. Cependant, pour moi (et d'autres aussi), qui arrive ici presque 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 (cela inclut aussi les pointeurs internes). Je suppose qu'il est temps pour moi de poser ma propre question.

39 votes

@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 construire un nouveau - De même, si le tableau source contient des objets, et que vous voulez les cloner, vous devrez le faire manuellement. Gardez aussi à l'esprit que les références en PHP sont no 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 les traiter comme des références ? Quel est le cas d'utilisation ?

2 votes

@troelskn J'ai ajouté une réponse à cette question avec une solution à mon problème : stackoverflow.com/a/17729234/1134804

244voto

Reinis I. Points 4089

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

0 votes

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 conduire à une moindre consommation de mémoire et à de meilleures performances (pas besoin de copier le tableau entier en mémoire).

22 votes

@robsch -- au niveau de la logique du programme, le tableau est copié. Mais en mémoire, il ne sera pas réellement copié jusqu'à ce qu'il soit modifié -- parce que PHP utilise la sémantique "copy-on-write" pour tous les types. stackoverflow.com/questions/11074970/

2 votes

@CoreyKnight Bon à savoir. Merci pour cela.

55voto

Andrew Larsson Points 239

Si vous avez un tableau qui contient des objets, que vous avez besoin de faire une copie de ce tableau sans toucher à son pointeur interne, et que vous avez besoin que tous les objets soient clonés (de sorte que vous ne modifiez pas les originaux lorsque vous apportez des changements au tableau copié), utilisez ceci.

L'astuce pour ne pas toucher au pointeur interne du tableau est de s'assurer que vous travaillez avec une copie du tableau, et non avec le tableau original (ou une référence à celui-ci), donc l'utilisation d'un paramètre de fonction fera l'affaire (ainsi, 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 tableaux mixtes).

function array_clone($array) {
    return array_map(function($element) {
        return ((is_array($element))
            ? array_clone($element)
            : ((is_object($element))
                ? clone $element
                : $element
            )
        );
    }, $array);
}

1 votes

N'oubliez pas qu'il s'agit d'un cas un peu particulier. Notez également que cela ne clonera que les références de premier niveau. Si vous avez un tableau profond, les noeuds les plus profonds ne seront pas clonés, s'ils sont des références. Ce n'est peut-être pas un problème dans votre cas, mais gardez-le à l'esprit.

5 votes

@troelskn Je l'ai corrigé en ajoutant un peu de récursivité. Cette fonction fonctionne maintenant sur n'importe quel type de tableau, y compris les types mixtes. Elle fonctionne aussi bien pour les tableaux simples, donc elle n'est plus localisée. Il s'agit en fait d'une machine universelle de clonage de tableaux. Vous aurez toujours besoin de définir la fonction __clone() dans vos objets s'ils sont profonds, mais c'est au-delà de la "portée" de cette fonction (désolé pour le mauvais jeu de mots).

2 votes

Je crois fermement que c'est la vraie réponse à cette question. C'est la seule façon que j'ai vue pour copier en profondeur un tableau contenant des objets.

30voto

chaos Points 69029

Quand vous le faites

$array_x = $array_y;

PHP copie le tableau, donc je ne vois pas comment vous auriez pu vous brûler. Pour votre cas,

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

devrait fonctionner correctement.

Pour être grillé, je pense qu'il faut soit utiliser des références, soit s'attendre à ce que les objets dans les tableaux soient clonés.

12 votes

+1 pour ça : "ou s'attendre à ce que les objets dans les tableaux soient clonés"

23voto

Kshitiz Saxena Points 119

array_merge() est une fonction qui vous permet de copier un tableau vers un autre en PHP.

5 votes

Oui, mais les clés seront modifiées, citez : Les valeurs du tableau d'entrée avec des clés numériques seront renumérotées avec des clés incrémentales à partir de zéro dans le tableau de résultat.

0 votes

@zamnuts pour le maintien des clés : $a_c = array_combine(array_keys($a), array_values($a)) .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X