Gibt es eine Funktion zum Erstellen einer Kopie eines PHP-Arrays in ein anderes?

529

Gibt es eine Funktion zum Erstellen einer Kopie eines PHP-Arrays in ein anderes?

Ich wurde einige Male beim Versuch, PHP-Arrays zu kopieren, verbrannt. Ich möchte ein innerhalb eines Objekts definiertes Array in ein globales außerhalb kopieren.

vfclists
quelle
sehr spät, aber in meiner Umgebung habe ich dies getestet (und es hat funktioniert): function arrayCopy (array $ a) {return $ a; } $ a1 = array (); für ($ i = 0; $ i <3; $ i ++) {$ a1 ["key- $ i"] = "Wert # $ i"; } $ a1 ["key-sub-array"] = array (1, 2, 3, 4); $ a2 = $ a1; $ a3 = arrayCopy ($ a1); für ($ i = 0; $ i <3; $ i ++) {if (! is_array ($ a2 ["key- $ i"])) {$ a2 ["key- $ i"] = "geänderter Wert # $ ich"; }} $ a2 ["key-sub-array"] = array ("geändertes sub-array 1", "geändertes sub-array 2"); var_dump ($ a1); var_dump ($ a2); var_dump ($ a3); Der Trick ist, das Array nicht als Referenz in die Funktion zu übergeben ;-)
Sven

Antworten:

926

In PHP werden Arrays durch Kopieren zugewiesen, während Objekte durch Referenz zugewiesen werden. Das bedeutet, dass:

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

Wird ergeben:

array(0) {
}

Wohingegen:

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

Ausbeuten:

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

Sie könnten durch Feinheiten wie verwirrt werden ArrayObject ein Objekt, das sich genau wie ein Array verhält. Als Objekt hat es jedoch eine Referenzsemantik.

Bearbeiten: @AndrewLarsson wirft einen Punkt in den Kommentaren unten auf. PHP hat eine spezielle Funktion namens "Referenzen". Sie ähneln Zeigern in Sprachen wie C / C ++, sind aber nicht ganz gleich. Wenn Ihr Array Referenzen enthält, werden die Referenzen weiterhin an das ursprüngliche Ziel aufgelöst, während das Array selbst kopiert wird. Das ist natürlich normalerweise das gewünschte Verhalten, aber ich fand es erwähnenswert.

troelskn
quelle
104
Du hast die Frage nicht beantwortet. Sie haben nur das Problem erklärt. Was für das OP höchstwahrscheinlich das ist, wonach er gesucht hat. Für mich (und auch für andere), die fast vier Jahre später mit einem ähnlichen Problem hierher kommen, habe ich jedoch immer noch keine gute Möglichkeit, ein Array zu klonen, ohne das ursprüngliche Array zu ändern (das auch interne Zeiger enthält). Ich nehme an, es ist Zeit für mich, meine eigene Frage zu stellen.
Andrew Larsson
28
@ AndrewLarsson Aber PHP macht das standardmäßig - das ist der Kern davon. Verweise werden jedoch nicht aufgelöst. Wenn Sie dies benötigen, müssen Sie das Array rekursiv durchlaufen und ein neues erstellen. Wenn das Quellarray Objekte enthält und diese geklont werden sollen, müssen Sie dies manuell tun. Denken Sie auch daran, dass Referenzen in PHP nicht mit Zeigern in C identisch sind. Ohne etwas über Ihren Fall zu wissen, kann ich vorschlagen, dass es seltsam ist, im ersten Fall eine Reihe von Referenzen zu haben, insbesondere wenn Sie nicht beabsichtigen, diese zu behandeln sie als Referenzen? Was ist der Anwendungsfall?
Troelskn
1
@troelskn Ich habe eine Antwort auf diese Frage mit einer Lösung für mein Problem hinzugefügt
Andrew Larsson
3
Aber was ist, wenn es nicht erwünschtes Verhalten ist? Die Frage fragt, wie man eine tiefe Kopie macht. Es ist offensichtlich nicht erwünscht. Ihre Antwort ist nicht besser als : $copy = $original;. Was nicht funktioniert, wenn die Array-Elemente Referenzen sind.
Doug65536
8
Wie immer phppräsentiert uns das am wenigsten erwartete Ergebnis , da diese Lösung nicht immer funktioniert . $a=array(); $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];druckt array0während $a=$GLOBALS; $b=$a; $b["x"]=0; $c=$b; $b["x"]=1; echo gettype($b), $c["x"];druckt array1. Anscheinend werden einige Arrays als Referenz kopiert.
Tino
186

PHP kopiert das Array standardmäßig. Referenzen in PHP müssen explizit sein.

$a = array(1,2);
$b = $a; // $b will be a different array
$c = &$a; // $c will be a reference to $a
slikts
quelle
Die Verwendung der Referenz kann wichtig sein, wenn das Array sehr groß ist. Ich bin nicht sicher, aber ich gehe davon aus, dass dies zu einem geringeren Speicherverbrauch und einer besseren Leistung führen sollte (es ist nicht erforderlich, das gesamte Array in den Speicher zu kopieren).
Robsch
11
@robsch - Auf der Ebene der Programmlogik wird das Array kopiert. Im Speicher wird es jedoch erst kopiert, wenn es geändert wurde - da PHP für alle Typen die Copant-on-Write-Semantik verwendet. stackoverflow.com/questions/11074970/…
Jessica Knight
@CoreyKnight Gut zu wissen. Danke dafür.
Robsch
4
Beachten Sie, dass dies nicht für verschachtelte Arrays gilt, da es sich um Referenzen handelt und Sie mit einem kaputten Durcheinander
enden
45

Wenn Sie ein Array haben, das Objekte enthält, müssen Sie eine Kopie dieses Arrays erstellen, ohne den internen Zeiger zu berühren, und Sie müssen alle Objekte klonen (damit Sie die Originale nicht ändern, wenn Sie Änderungen am kopierten Objekt vornehmen Array), benutze dies.

Der Trick, den internen Zeiger des Arrays nicht zu berühren, besteht darin, sicherzustellen, dass Sie mit einer Kopie des Arrays arbeiten und nicht mit dem ursprünglichen Array (oder einem Verweis darauf). Wenn Sie also einen Funktionsparameter verwenden, wird die Aufgabe erledigt (also Dies ist eine Funktion, die ein Array aufnimmt.

Beachten Sie, dass Sie __clone () weiterhin für Ihre Objekte implementieren müssen, wenn deren Eigenschaften auch geklont werden sollen.

Diese Funktion funktioniert für jeden Array-Typ (einschließlich gemischter Typen).

function array_clone($array) {
    return array_map(function($element) {
        return ((is_array($element))
            ? array_clone($element)
            : ((is_object($element))
                ? clone $element
                : $element
            )
        );
    }, $array);
}
Andrew Larsson
quelle
1
Denken Sie daran, dass dies ein Sonderfall ist. Beachten Sie außerdem, dass dadurch nur die Referenzen der ersten Ebene geklont werden. Wenn Sie ein tiefes Array haben, werden die tieferen Knoten nicht geklont, wenn es sich um Referenzen handelt. Könnte in Ihrem Fall kein Problem sein, aber denken Sie daran.
Troelskn
4
@troelskn Ich habe es behoben, indem ich eine Rekursion hinzugefügt habe. Diese Funktion funktioniert jetzt für alle Arten von Arrays, einschließlich gemischter Typen. Es funktioniert auch genauso gut für einfache Arrays, sodass es nicht mehr lokalisiert ist. Es ist im Grunde eine universelle Array-Klonmaschine. Sie müssten die __clone () -Funktion in Ihren Objekten noch definieren, wenn sie tief sind, aber das würde den "Umfang" dieser Funktion sprengen (entschuldigen Sie das schlechte Wortspiel).
Andrew Larsson
2
Ich bin der festen Überzeugung, dass dies die eigentliche Antwort auf diese Frage ist. Der einzige Weg, den ich gesehen habe, um ein Array, das Objekte enthält, tatsächlich tief zu kopieren.
Patrick
Objekteigenschaften, die möglicherweise andere Arrays und referenzierte Objekte enthalten, werden nicht iteriert.
ya.teck
6
Diese Verwendung von __FUNCTION__ist brillant.
Zessx
29

Wenn Sie das tun

$array_x = $array_y;

PHP kopiert das Array, daher bin ich mir nicht sicher, wie Sie sich verbrannt hätten. Für Ihren Fall

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

sollte gut funktionieren.

Um verbrannt zu werden, müssten Sie entweder Referenzen verwendet haben oder erwarten, dass Objekte in den Arrays geklont werden.

Chaos
quelle
12
+1 dafür: "oder erwarten, dass Objekte in den Arrays geklont werden"
Melsi
20

array_merge() ist eine Funktion, mit der Sie ein Array in PHP in ein anderes kopieren können.

Kshitiz Saxena
quelle
4
Ja, aber die Schlüssel werden geändert. Zitat: Werte im Eingabearray mit numerischen Schlüsseln werden mit inkrementierenden Schlüsseln beginnend mit Null im Ergebnisarray neu nummeriert.
Zamnuts
@ zamnuts zur Pflege von Schlüsseln : $a_c = array_combine(array_keys($a), array_values($a)).
CPHPython
18

einfach und macht tiefe Kopie alle Links zu brechen

$new=unserialize(serialize($old));
Matthew Cornelisse
quelle
4
Im Allgemeinen funktioniert es einwandfrei, in einigen Fällen kann jedoch eine Ausnahme ausgelöst werden, da nicht alle Variablen serialisierbar sind (z. B. Schließungen und Datenbankverbindungen).
ya.teck
Beachten Sie außerdem, dass Objektreferenzen wiederhergestellt werden können, wenn eine Klasse die magische Methode __wakeup implementiert.
ya.teck
Danke, endlich etwas, das wirklich funktioniert, nicht die anderen Bollock-Antworten mit vielen positiven Stimmen, sie haben sich sicherlich nicht mit Arrays von Objekten befasst, wie in der Frage angegeben, wo sich die Anzahl der Elemente im Array ändern könnte, aber definitiv nicht mit den Verweisen auf das Objekte in ihnen
FentomX1
12

Ich mag array_replace(oder array_replace_recursive).

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

Es funktioniert wie mit Object.assignJavaScript.

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

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

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

wird darin enden, dass

// 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"}
Putzi San
quelle
1
Was ist mit array_slice($arr, 0)oder wenn Sie sich nicht für Schlüssel interessieren array_values($arr)? Ich denke, sie sind möglicherweise schneller als die Suche in einem Array. In Javascript ist es auch sehr beliebt, Array.slice()Arrays zu klonen.
Christian
In JS haben wir Object für Schlüssel-Wert-Paare und Array . PHP macht diesen Unterschied nicht. Für PHP-Arrays mit nummerierten Indizes array_slicefunktionieren alle anderen hier genannten Methoden sehr gut. Wenn Sie jedoch mehrere Schlüssel-Wert-Paare zusammenführen möchten (wie dies auch bei JS-Objekten über Object.assignoder über die Spread-Syntax möglich ist ), array_replacekann dies nützlicher sein.
Putzi San
@Christian danke für den Vorschlag, der array_values()perfekt für meinen Anwendungsfall funktioniert hat.
Bigsee
11

Wenn Ihr Array nur grundlegende Typen enthält, können Sie dies tun:

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

Sie müssen die Referenzen nicht manuell aktualisieren.
Ich weiß, dass es nicht für alle funktioniert, aber es hat für mich funktioniert

chrmcpn
quelle
4
+1 das ist eine wirklich schlechte Sache, aber technisch korrekt und klug. Wenn ich das im Code sehen würde, würde ich mich der Handfläche stellen, aber ich kann nicht anders, als es zu mögen.
Reactgular
4

Da dies in keiner der Antworten behandelt wurde und jetzt in PHP 5.3 verfügbar ist (vorausgesetzt, Original Post verwendete 5.2).

Um eine Array-Struktur beizubehalten und ihre Werte zu ändern, bevorzuge ich die Verwendung array_replaceoder array_replace_recursiveabhängig von meinem Anwendungsfall.

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

Hier ist ein Beispiel, in dem verwendet array_replaceund array_replace_recursivedemonstriert wird, dass die indizierte Reihenfolge beibehalten und eine Referenz entfernt werden kann.

http://ideone.com/SzlBUZ

Der folgende Code geschrieben wird mit der kurzen Array - Syntax verfügbar seit PHP 5.4 die an der Stelle array()mit []. http://php.net/manual/en/language.types.array.php

Funktioniert mit Offset-indizierten und namenindizierten Arrays

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

Ausgabe:

["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"
  }
fyrye
quelle
3

Ich weiß das schon vor langer Zeit, aber das hat bei mir funktioniert.

$copied_array = array_slice($original_array,0,count($original_array));
bestprogrammerintheworld
quelle
2

So kopiere ich meine Arrays 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);

Dies gibt aus:

Array
(
[0] => aa
[1] => bb
[2] => 3
)
Baykal
quelle
2
Warum nicht einfach sagen $test2 = $test;? Welches Problem ArrayObjectlöst sich hier?
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;
}
?>
umair
quelle
1

Der sicherste und billigste Weg, den ich gefunden habe, ist:

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

Dies hat auch den Vorteil, dass das Array neu indiziert wird.

Dies funktioniert nicht wie erwartet für assoziatives Array (Hash), aber auch nicht für die meisten vorherigen Antworten.

Hussard
quelle
1

Erstellt eine Kopie des 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);

?>

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

kheengz
quelle
0

Definieren Sie dies:

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

Kopieren Sie $ _ARRAY nach $ _ARRAY2:

$_ARRAY2 = array_map($copy, $_ARRAY);
Oscar Gardiazabal
quelle
0

Im PHP-Array müssen Sie sie nur einer anderen Variablen zuweisen, um eine Kopie dieses Arrays zu erhalten. Aber zuerst müssen Sie sicherstellen, dass es sich um einen Typ handelt, ob es sich um Array oder ArrayObject oder StdObject handelt.

Für einfaches PHP-Array:

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

$b = $a;

var_dump($b);

output:

array:1 [
  "data" => 10
]
MAULIK MODI
quelle
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;
    }
}
Artemiy StagnantIce Alexeew
quelle
0

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

Nur um noch eine Lösung zu posten;)

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

Erhält sowohl Schlüssel als auch Werte. Array 'a' ist eine exakte Kopie von Array 'b'

Krish PG
quelle