wake-up-neo.com

Wie kann ich ein Array von Objekten in PHP klonen?

Ich habe eine Reihe von Objekten. Ich weiß, dass Objekte durch "Referenz" und Arrays durch "Wert" zugewiesen werden. Wenn ich jedoch das Array zuweise, referenziert jedes Element des Arrays auf das Objekt. Wenn ich also ein Objekt in einem der Arrays ändere, werden die Änderungen in dem anderen Array angezeigt.

Gibt es eine einfache Möglichkeit, ein Array zu klonen, oder muss ich es durchlaufen, um jedes Objekt zu klonen?

53
DisgruntledGoat

Verweise auf dieselben Objekte werden bereits beim Kopieren des Arrays kopiert. Aber es klingt wie du willst flache Kopie Kopieren Sie die Objekte, auf die im ersten Array verwiesen wird, beim Erstellen des zweiten Arrays tief, sodass Sie zwei Arrays mit unterschiedlichen, aber ähnlichen Objekten erhalten.

Der intuitivste Weg, auf den ich jetzt kommen kann, ist eine Schleife; Es kann einfachere oder elegantere Lösungen geben:

$new = array();

foreach ($old as $k => $v) {
    $new[$k] = clone $v;
}
43
BoltClock
$array = array_merge(array(), $myArray);
66
erani

Sie müssen Objekte klonen, um Verweise auf dasselbe Objekt zu vermeiden.

function array_copy($arr) {
    $newArray = array();
    foreach($arr as $key => $value) {
        if(is_array($value)) $newArray[$key] = array_copy($value);
        else if(is_object($value)) $newArray[$key] = clone $value;
        else $newArray[$key] = $value;
    }
    return $newArray;
}
18
Daniel Teichman

Wie von AndreKR vorgeschlagen, ist die Verwendung von array_map () der beste Weg, wenn Sie bereits wissen, dass Ihr Array Objekte enthält:

$clone = array_map(function ($object) { return clone $object; }, $array);
13

Ich entschied mich auch für Klon. Das Klonen eines Arrays funktioniert nicht (Sie könnten in Betracht ziehen, dass eine Arrayaccess-Implementierung für Sie durchgeführt wird), z. B. für das array clone mit array_map :

class foo {
    public $store;
    public function __construct($store) {$this->store=$store;}
}

$f = new foo('moo');
$a = array($f);

$b = array_map(function($o) {return clone $o;}, $a);

$b[0]->store='bar';    
var_dump($a, $b);

Array-Klon mit serialisieren und unserialisieren

Wenn Ihre Objekte die Serialisierung unterstützen, können Sie sogar eine Art deep shallow copy/clone mit einer Tour in ihren Schlafzustand und zurück ausführen:

$f = new foo('moo');
$a = array($f);

$b = unserialize(serialize($a));

$b[0]->store='bar';
var_dump($a, $b);

Das kann jedoch etwas abenteuerlich sein.

5
hakre

Ich habe es so gemacht:

function array_clone($array) {
    array_walk_recursive($array, function(&$value) {
        if(is_object($value)) {
            $value = clone $value;
        }
    });
    return $array;
}

Die Funktion arg kopiert das Array, ohne die Objekte zu klonen.... Dann wird jedes verschachtelte Objekt geklont. Es funktioniert also nicht, wenn der Algorithmus nicht innerhalb einer Funktion verwendet wird.

Beachten Sie, dass diese Funktion das Array rekursiv kopiert. Sie können array_walk anstelle von array_walk_recursive verwenden, wenn Sie dies nicht möchten.

2
nuKs

Hier ist meine beste Praxis für eine Reihe von Objekten und das Klonen. Normalerweise empfiehlt es sich, für jede Klasse von Objekten (oder Schnittstellen), die in einem Array verwendet werden, eine Collection-Klasse zu haben. Mit der Zauberfunktion __clone wird das Klonen zu einer formalisierten Routine:

class Collection extends ArrayObject
{
     public function __clone()
     {
        foreach ($this as $key => $property) {
            $this[$key] = clone $property;
        }
     }
}

Um Ihr Array zu klonen, verwenden Sie es als Collection und dann klonen Sie es:

$arrayObject = new Collection($myArray);
$clonedArrayObject = clone $arrayObject;

Einen Schritt weiter sollten Sie Ihrer Klasse und jeder Unterklasse auch eine Klonmethode hinzufügen. Dies ist wichtig für tiefes Klonen. Andernfalls können unerwünschte Nebenwirkungen auftreten:

class MyClass
{
     public function __clone()
     {
        $this->propertyContainingObject = clone $this->propertyContainingObject;
     }
}

Ein wichtiger Hinweis zur Verwendung von ArrayObject ist, dass Sie is_array() nicht mehr verwenden können. Beachten Sie dies beim Refactoring Ihres Codes.

2
Trendfischer

Sie müssen es schleifen (möglicherweise unter Verwendung einer Funktion wie array_map()). Es gibt keine PHP - Funktion, um automatisch eine tiefe Kopie eines Arrays durchzuführen.

2
AndreKR

Für PHP 5 und höher kann ArrayObject cunstructur verwendet werden, um ein Array wie folgt zu klonen:

$myArray = array(1, 2, 3);
$clonedArray = new ArrayObject($myArray);
0

Wenn Sie ein multidimensionales Array oder ein Array aus beiden Objekten und anderen Werten haben, können Sie diese Methode verwenden:

$cloned = Arr::clone($array);

aus dieser Bibliothek .

0
Minwork

Objekte werden standardmäßig von point übergeben und sind nicht immer leicht zu klonen, zumal sie zirkuläre Referenzen haben. Bei einer anderen Auswahl von Datenstrukturen wären Sie besser geeignet.

Für diejenigen, die Lösungen für flaches Kopieren anbieten, ist dies der einfachere Weg:

 $b = (array)$a;

Für tiefe Exemplare empfehle ich diese Lösung nicht:

$ nuarr = json_decode (json_encode ($ array));

Dies ist für eine tiefe Kopie. Es unterstützt nur eine Teilmenge von PHP - Typen und tauscht Objekte in Arrays oder Arrays in Objekte aus, die möglicherweise nicht Ihren Vorstellungen entsprechen und möglicherweise binäre Werte beschädigen und so weiter.

Wenn Sie eine manuelle rekursive Funktion für tiefe Kopien erstellen, ist der Speicherbedarf für Skalarwerte und Schlüssel viel geringer, so dass die Verwendung von json oder einem anderen Serializer eine Auswirkung auf den Ausführungszeitpunkt hat.

Es ist möglicherweise besser, unserialize (serialize ($ a)) für tiefe Kopien zu verwenden, wenn die Leistung kein Problem darstellt, das eine breitere Unterstützung für Dinge wie Objekte bietet, obwohl ich nicht überrascht wäre, wenn Zirkelverweise und einige andere ungewöhnliche Dinge auftreten.

array_merge_recursive oder array_walk_recursive können auch für Arrays verwendet werden.

Sie können einfach Ihre eigene rekursive Funktion erstellen, die is_object und is_array verwendet, um die geeigneten Kopiermittel auszuwählen.

0
jgmjgm

oder auch

$nuarr = json_decode(json_encode($array));

aber es ist teuer, ich bevorzuge Sebastien Version (array_map)

0