PHP 5: Objekte klonen

Manchmal möchte man explizit eine Kopie eines Objekts anlegen, etwa um sicherzustellen, dass eine mit dem Objekt als Parameter aufgerufene Funktion die Daten wirklich unangetastet lässt.

Ein anderer Grund wäre die Notwendigkeit eines neuen Objekts, das einem existierenden Objekt nahezu gleicht. Dann würde man das eine kopieren und lediglich die abweichenden Eigenschaften abändern.

Die explizite Vervielfältigung eines Objekts ist möglich. Dafür ist der Befehl clone zuständig. Eine Kopie legt man durch folgende Anweisung an:

$objKopie = clone $objOriginal;

Damit erreicht man also im Prinzip dasselbe wie mit new und der Nennung des jeweiligen Klassennamens. Allerdings weist das über die Clone-Variante erzeugte neue Objekt nach dem Kopiervorgang bereits besetzte Instanzvariablen auf, die mit denen des Originals absolut übereinstimmen.

<?php

// Beispiel – OOP

// Klonen von Objekten

class AutoKlasse {

   var $strMarke, $strTyp, $nBaujahr;

  

   function AutoKlasse($strMarke, $strTyp, $nBaujahr){

   $this->strMarke=$strMarke;

   $this->strTyp=$strTyp;

   $this->nBaujahr=$nBaujahr;

   }

  

}

$objA = new AutoKlasse(‘Mercedes’,’300 SL’,1954);

$objB = clone $objA;

$objB->nBaujahr=1990;

echo $objA->nBaujahr . ‘<br>’;

echo $objB->nBaujahr . ‘<br>’;

?>

In diesem Beispiel hat die AutoKlasse einen Konstruktor, der die Instanzvariablen für Marke, Typ und Baujahr festlegt. Im geklonten Objekt B wird das Baujahr verändert. Die Ausgabe dieses Skripts wird die beiden Baujahre 1954 und 1990 ausgeben, weil die Objekte tatsächlich verschieden sind. Sie sehen: Es handelt sich nicht bloß um zwei Referenzen auf dasselbe Objekt.

Obwohl die vordefinierte Methode zum Klonen von Objekten brav alle Instanzvariablen kopiert, ist das nicht immer die gewünschte Verhaltensweise. Enthält das Objekt zum Beispiel eine eindeutige Identifikation (wie einen Zähler für das Objekt) oder Referenzen auf externe Daten (z. B. auf Dateien), dann möchte man diese Eigenschaften des Objekts lieber unter eigener Kontrolle in der Kopie des existierenden Objekts setzen.

Ein anderer Aspekt ist die Verschachtelung von Objekten. Wenn eine Klasse als Instanzvariablen wiederum andere Objekte besitzt, dann wird beim Klonen dieses enthaltene innere Objekt nicht mitkopiert, sondern nur die Referenz. Wollen Sie erreichen, dass in der Kopie des »Mutterobjekts« dieses enthaltene Objekt auch eine eigenständige Kopie ist, müssen Sie das selbst erledigen.

Für solche speziellen Eingriffe gibt es die Möglichkeit, den vordefinierten Methodenamen

__clone

mit eigenem Programmcode zu füllen. Er wird dann aufgerufen, wenn ein Skript über den Befehl clone die Kopie eines Objekts dieser Klasse anfordert. Die Abfolge ist dann so, dass zuerst der integrierte Kloner aktiv wird, also alle Instanzvariablen auf die Kopie übertragen werden. Beim Eintritt in die

__clone

-Methode hat das neue Objekt also bereits besetzte Variablen.

Genug der Theorie – nun folgt ein Beispiel dafür, wie man selbst in den Klonvorgang eingreift. Zugrunde liegt folgende Objektmodellierung: Es gibt eine allgemeine Fahrzeugklasse. Diese besitzt eine Instanzvariable zum Speichern des Baujahrs sowie ein Objekt, das Informationen zur Identifikation enthält – hier die Fahrgestellnummer und den Herstellercode. Das würde man in Wirklichkeit nicht so kompliziert lösen; ein echtes Beispiel, in dem Objekte als Instanzvariablen benötigt werden, würde aber den Rahmen dieses Kapitels sprengen.

Damit der Klon einer Instanz der Fahrzeugklasse nicht einfach die Objektreferenz seiner Kopiervorlage – und damit deren Identifikation – übernimmt, wird die Methode __clone mit Leben gefüllt. In unserem Beispiel sorgt sie dafür, dass ein neues Objekt entsteht und dessen Identifikationsdaten mit einem Default-Wert belegt werden:

<?php

// Beispiel – OOP

// Einsatz einer eigenen clone-Funktion

class FzgIdentifikationKlasse {

   var $strFgstNr;

   var $strHerstNr;

   }

class FahrzeugKlasse {

   var $objId;

   var $nBaujahr;

  

   function __clone() {

      $this->objId = new FzgIdentifikationKlasse();

      $this->objId->strFgstNr =’unbelegt’;

      $this->objId->strHerstNr=’unbelegt’;

      }

      

   }

class AutoKlasse extends FahrzeugKlasse{

   var $strMarke, $strTyp;

  

   function AutoKlasse($strMarke, $strTyp, $nBaujahr, $strFzgNr, $strHerstNr){

      $this->strMarke=$strMarke;

      $this->strTyp=$strTyp;

      $this->nBaujahr=$nBaujahr;

      $this->objId->strFgstNr =$strFzgNr;

      $this->objId->strHerstNr=$strHerstNr;

      

   }

   function __clone() {

      FahrzeugKlasse::__clone();

      }

   function getDaten(){

      $strTmp = ‘Ich bin ein ‘ . $this->strMarke;

      $strTmp .= ‘ ‘ . $this->strTyp . ‘<br>’;

      $strTmp .= ‘Baujahr ‘ . $this->nBaujahr .'<br>’;

      $strTmp .= ‘Fzg-Nr ‘ . $this->objId->strFgstNr;

      $strTmp .= ‘<br>’ . ‘Herstellercode ‘;

      $strTmp .= $this->objId->strHerstNr .'<br><hr>’;

      return $strTmp;

      }   }

$objFzg1 = new AutoKlasse(‘Mercedes’,’300 SL’,1954,’11111′,’0710′);

$objFzg2 = clone $objFzg1;

// Die vom Fzg1 verschiedenen Eigenschaften des neuen

// Fahrzeugs werden gesetzt.

$objFzg2->nBaujahr=’1955′;

$objFzg2->objId->strFgstNr=’22222′;

echo ‘Fahrzeug 1:<br>’ . $objFzg1->getDaten();

echo ‘Fahrzeug 2 (geklont):<br>’ . $objFzg2->getDaten();

?>

Ähnliche Beiträge