Esiste una funzione per fare una copia di un array PHP su un altro?


530

Esiste una funzione per fare una copia di un array PHP su un altro?

Sono stato bruciato alcune volte nel tentativo di copiare array di PHP. Voglio copiare un array definito all'interno di un oggetto in un globale esterno ad esso.


molto tardi, ma nel mio ambiente ho provato questo (e ha funzionato): function arrayCopy (array $ a) {return $ a; } $ a1 = array (); per ($ i = 0; $ i <3; $ i ++) {$ a1 ["key- $ i"] = "valore # $ i"; } $ a1 ["key-sub-array"] = array (1, 2, 3, 4); $ a2 = $ a1; $ a3 = arrayCopy ($ a1); per ($ i = 0; $ i <3; $ i ++) {if (! is_array ($ a2 ["key- $ i"])) {$ a2 ["key- $ i"] = "ha cambiato il valore # $ io"; }} $ a2 ["key-sub-array"] = array ("sub-array 1 modificato," sub-array 2 modificato "); var_dump ($ A1); var_dump ($ a2); var_dump ($ a3); Il trucco è, non passare l'array come riferimento nella funzione ;-)
Sven

Risposte:


927

In PHP gli array sono assegnati per copia, mentre gli oggetti sono assegnati per riferimento. Ciò significa che:

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

Produrrà:

array(0) {
}

Mentre:

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

I rendimenti:

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

Potresti essere confuso da complessità come ArrayObject, che è un oggetto che si comporta esattamente come un array. Essendo un oggetto, tuttavia, ha una semantica di riferimento.

Modifica: @AndrewLarsson solleva un punto nei commenti qui sotto. PHP ha una funzione speciale chiamata "riferimenti". Sono in qualche modo simili ai puntatori in linguaggi come C / C ++, ma non sono uguali. Se l'array contiene riferimenti, mentre l'array stesso viene passato per copia, i riferimenti verranno comunque risolti nella destinazione originale. Questo è ovviamente il comportamento desiderato, ma ho pensato che valesse la pena menzionarlo.


104
Non hai risposto alla domanda. Hai solo spiegato il problema. Che, per l'OP, è molto probabilmente quello che stava cercando. Tuttavia, per me (e anche per altri), venendo qui quasi quattro anni dopo con un problema simile, non ho ancora un buon modo per clonare un array senza modificare l'array originale (che include anche i puntatori interni). Suppongo che sia tempo per me di porre la mia domanda.
Andrew Larsson,

28
@AndrewLarsson Ma PHP lo fa di default - Questa è la sostanza. Tuttavia, i riferimenti non vengono risolti, quindi se ne hai bisogno, dovrai attraversare ricorsivamente l'array e crearne uno nuovo - Allo stesso modo, se l'array di origine contiene oggetti e desideri che vengano clonati, dovrai farlo manualmente. Tieni presente anche che i riferimenti in PHP non sono gli stessi puntatori in C. Senza sapere nulla del tuo caso, posso suggerire che è strano avere una serie di riferimenti nel primo caso, specialmente se non intendi trattare loro come riferimenti? Qual è il caso d'uso?
troelskn,

1
@troelskn Ho aggiunto una risposta a questa domanda con una soluzione al mio problema: stackoverflow.com/a/17729234/1134804
Andrew Larsson,

3
Ma che dire quando non si desidera il comportamento? La domanda si pone come fare una copia profonda . Ovviamente non è desiderato. La tua risposta non è migliore di quanto non sia: $copy = $original;. Che non funziona se gli elementi dell'array sono riferimenti.
doug65536,

8
Come sempre phpci presenta il risultato meno atteso , perché questa soluzione non sempre funziona . $a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];stampe array0mentre $a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];stampe array1. Apparentemente alcuni array vengono copiati per riferimento.
Tino,

186

PHP copierà l'array per impostazione predefinita. I riferimenti in PHP devono essere espliciti.

$a = array(1,2);
$b = $a; // $b will be a different array
$c = &$a; // $c will be a reference to $a

Utilizzare il riferimento potrebbe essere importante se l'array è enorme. Non sono sicuro, ma presumo che dovrebbe portare a un minor consumo di memoria e prestazioni migliori (non è necessario copiare l'intero array in memoria).
robsch,

11
@robsch: a livello di logica del programma, l'array viene copiato. Ma in memoria, in realtà non verrà copiato fino a quando non verrà modificato, poiché PHP utilizza la semantica copy-on-write per tutti i tipi. stackoverflow.com/questions/11074970/…
Jessica Knight il

@CoreyKnight Buono a sapersi. Grazie per questo.
robsch,

4
nota che questo non è vero per le matrici nidificate, sono riferimenti e quindi
finisci

45

Se si dispone di un array che contiene oggetti, è necessario effettuare una copia di tale array senza toccare il puntatore interno e è necessario clonare tutti gli oggetti (in modo da non modificare gli originali quando si apportano modifiche alla copia array), usa questo.

Il trucco per non toccare il puntatore interno dell'array è assicurarsi di lavorare con una copia dell'array e non con l'array originale (o un riferimento ad esso), quindi l'utilizzo di un parametro funzione consentirà di eseguire il lavoro (quindi, questa è una funzione che accetta un array).

Tieni presente che dovrai comunque implementare __clone () sui tuoi oggetti se desideri che anche le loro proprietà vengano clonate.

Questa funzione è disponibile per qualsiasi tipo di array (incluso il tipo misto).

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

1
Tieni presente che questo è un po 'un caso speciale. Inoltre, tieni presente che questo clonerà solo i riferimenti di primo livello. Se hai un array profondo, non otterrai la clonazione dei nodi più profondi, se sono riferimenti. Potrebbe non essere un problema nel tuo caso, ma tienilo a mente.
troelskn,

4
@troelskn L'ho risolto aggiungendo un po 'di ricorsione. Questa funzione ora funzionerebbe su qualsiasi tipo di array, inclusi i tipi misti. Funziona altrettanto bene anche per array semplici, quindi non è più localizzato. È fondamentalmente una macchina universale per la clonazione di array. Avresti ancora bisogno di definire la funzione __clone () nei tuoi oggetti se sono profondi, ma questo va oltre lo "scopo" di questa funzione (scusami per il brutto gioco di parole).
Andrew Larsson,

2
Credo fermamente che questa sia la vera risposta a questa domanda, l'unico modo che ho visto per copiare in profondità un array che contiene oggetti.
Patrick,

Non itera le proprietà degli oggetti che possono avere altre matrici e oggetti referenziati.
ya.teck

6
Questo uso di __FUNCTION__è geniale.
Zessx,

29

Quando lo fai

$array_x = $array_y;

PHP copia l'array, quindi non sono sicuro di come ti saresti bruciato. Per il tuo caso,

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

dovrebbe funzionare bene.

Per essere bruciato, penso che dovresti aver usato i riferimenti o aspettarti che gli oggetti all'interno degli array vengano clonati.


12
+1 per questo: "o aspettandosi che gli oggetti all'interno degli array vengano clonati"
Melsi


18

semplice e rende la copia profonda interrompendo tutti i collegamenti

$new=unserialize(serialize($old));

4
In genere funziona bene, tuttavia in alcuni casi potrebbe generare un'eccezione perché non tutte le variabili sono serializzabili (ad esempio chiusure e connessioni al database).
ya.teck

Un'altra cosa da notare è che i riferimenti agli oggetti possono essere ripristinati se una classe implementa il metodo magico __wakeup.
ya.teck

Grazie, finalmente qualcosa che funziona davvero, non gli altri bollock rispondono con molti voti positivi, sicuramente non hanno affrontato l'array di oggetti come è specificato nella domanda in cui il numero di elementi nell'array potrebbe cambiare, ma sicuramente non i riferimenti al oggetti al loro interno
FentomX1

12

Mi piace array_replace(o array_replace_recursive).

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

Funziona come Object.assignda 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';

si tradurrà in

// 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"}

1
Che dire array_slice($arr, 0)o quando non ti interessano le chiavi array_values($arr)? Sto pensando che potrebbero essere più veloci della ricerca in un array. Inoltre, in JavaScript, è abbastanza popolare usare Array.slice()per clonare array.
Christian,

In JS abbiamo Object per coppie chiave-valore e array . PHP non fa questa differenza. Per gli array PHP con indici numerati array_slicee tutti gli altri metodi citati qui funzionano molto bene. Ma se vuoi unire più coppie chiave-valore (come è anche possibile con JS-Objects tramite Object.assigno la sintassi di diffusione ), array_replacepuò essere più utile.
Putzi San

@Christian grazie per il suggerimento di array_values()cui ha funzionato perfettamente per il mio caso d'uso.
ciao

11

Se nell'array sono presenti solo tipi di base, è possibile procedere come segue:

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

Non dovrai aggiornare i riferimenti manualmente,
so che non funzionerà per tutti, ma ha funzionato per me


4
+1 questa è una brutta cosa da fare, ma è tecnicamente corretta e intelligente. Se lo vedessi nel codice, affronterei il palmo della mano ma non posso fare a meno di apprezzarlo.
Reactgular

4

Dal momento che questo non è stato trattato in nessuna delle risposte ed è ora disponibile in PHP 5.3 (supponendo che Original Post stesse usando 5.2).

Per mantenere una struttura di array e modificarne i valori, preferisco usare array_replaceo in array_replace_recursivebase al mio caso d'uso.

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

Ecco un esempio usando array_replacee array_replace_recursivedimostrando che è in grado di mantenere l'ordine indicizzato e in grado di rimuovere un riferimento.

http://ideone.com/SzlBUZ

Il codice seguente è scritto usando la sintassi di array corta disponibile da PHP 5.4 che sostituisce array() con []. http://php.net/manual/en/language.types.array.php

Funziona su array indicizzati offset e nominali

$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);

Produzione:

["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

Lo so molto tempo fa, ma ha funzionato per me ..

$copied_array = array_slice($original_array,0,count($original_array));

2

Questo è il modo in cui sto copiando i miei array in Php:

function equal_array($arr){
  $ArrayObject = new ArrayObject($arr);
  return $ArrayObject->getArrayCopy();  
}

$test = array("aa","bb",3);
$test2 = equal_array($test);
print_r($test2);

Questo produce:

Array
(
[0] => aa
[1] => bb
[2] => 3
)

2
Perché non dirlo $test2 = $test;? Quale problema sta ArrayObjectrisolvendo qui?
Nate,

1
<?php
function arrayCopy( array $array ) {
        $result = array();
        foreach( $array as $key => $val ) {
            if( is_array( $val ) ) {
                $result[$key] = arrayCopy( $val );
            } elseif ( is_object( $val ) ) {
                $result[$key] = clone $val;
            } else {
                $result[$key] = $val;
            }
        }
        return $result;
}
?>

1

Il modo più sicuro ed economico che ho trovato è:

<?php 
$b = array_values($a);

Questo ha anche il vantaggio di reindicizzare l'array.

Questo non funzionerà come previsto sull'array associativo (hash), ma nemmeno sulla maggior parte delle risposte precedenti.


1

Crea una copia di ArrayObject

<?php
// Array of available fruits
$fruits = array("lemons" => 1, "oranges" => 4, "bananas" => 5, "apples" => 10);

$fruitsArrayObject = new ArrayObject($fruits);
$fruitsArrayObject['pears'] = 4;

// create a copy of the array
$copy = $fruitsArrayObject->getArrayCopy();
print_r($copy);

?>

da https://www.php.net/manual/en/arrayobject.getarraycopy.php


0

Definisci questo:

$copy = create_function('$a', 'return $a;');

Copia $ _ARRAY in $ _ARRAY2:

$_ARRAY2 = array_map($copy, $_ARRAY);

0

Nell'array php, devi semplicemente assegnarli ad altre variabili per ottenere una copia dell'array. Ma prima devi assicurarti del tipo, che si tratti di array o arrayObject o stdObject.

Per array php semplice:

$a = array(
'data' => 10
);

$b = $a;

var_dump($b);

output:

array:1 [
  "data" => 10
]

0
private function cloneObject($mixed)
{
    switch (true) {
        case is_object($mixed):
            return clone $mixed;
        case is_array($mixed):
            return array_map(array($this, __FUNCTION__), $mixed);
        default:
            return $mixed;
    }
}

0

$arr_one_copy = array_combine(array_keys($arr_one), $arr_one);

Solo per pubblicare un'altra soluzione;)


-1
foreach($a as $key => $val) $b[$key] = $val ;

Conserva sia la chiave che i valori. La matrice 'a' è una copia esatta della matrice 'b'

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.