Referenzen

Der new-Operator erzeugt ein neues Exemplar einer Klasse, ein Objekt. Als Rückgabe liefert er eine Referenz auf dieses neue Objekt. Diese Referenz wird in einer Variablen abgelegt. Über diese Variable kann das Objekt im Programm angesprochen werden.

Der PHP-Interpreter unterscheidet Objekte anhand einer eindeutigen ID, die er beim Anlegen des Objektes vergibt. Um zu testen, ob zwei Variablen dasselbe Objekt referenzieren, kann der Operator === verwendet werden.

Beispiel 1.8: Überprüfung der Objektidentität mit dem === Operator

<?php
class Klasse {
}
 
$a = new Klasse;
$b = $a;
 
if ($a === $b) {
  print '$a und $b referenzieren dasselbe Objekt.' . "\n";
}
?>
$a und $b referenzieren dasselbe Objekt.


Enthält keine Variable mehr eine Referenz auf ein Objekt, so wird es gelöscht und der belegte Speicher wird freigegeben (Garbage Collection).

Eine besondere Referenz enthält die Pseudovariable $this. Über diese kann ein Objekt auf seine eigenen Instanzvariablen und Methoden zugreifen. So wird in Beispiel 1.9 die Instanzvariable $variable des Objektes gesetzt, das durch die Variable $objekt referenziert wird.

Beispiel 1.9: Verwendung der Pseudovariablen $this

<?php
class Klasse {
  private $variable;
 
  public function setzeVariable($neuerWert) {
    $this->variable = $neuerWert;
  }
}
 
$objekt = new Klasse;
$objekt->setzeVariable('test');
?>


Das Ablegen einer Referenz auf ein anderes Objekt in einer Instanzvariablen eines Objektes nennt man Aggregation. Man sagt in solch einem Fall, dass ein Objekt ein anderes aggregiert. Leitet ein Objekt einen Methodenaufruf an ein aggregiertes Objekt weiter, so spricht man von Delegation.

Manchmal möchte man anstelle einer Referenz eine Kopie eines Objektes verwenden. Beispielsweise wenn einer Methode ein Objekt als Parameter übergeben wird, man dieses Objekt aber nicht nach außen sichtbar verändern möchte. Mit dem clone-Operator kann man eine solche Kopie eines Objektes erzeugen.

Die Anwendung des clone-Operators auf ein Objekt erzeugt eine exakte Kopie desselben und liefert eine Referenz auf dieses neue Objekt.

Beispiel 1.10: Klonen von Objekten

<?php
class Klasse {
}
 
$original = new Klasse;
$kopie    = clone $original;
 
if ($original !== $kopie) {
  print '$original und $kopie referenzieren nicht ' .
        "dasselbe Objekt.\n";
}
?>
$original und $kopie referenzieren nicht dasselbe Objekt.


Wird keine exakte Kopie eines Objektes gewünscht, so kann der Kopiervorgang in der entsprechenden Klasse mit einer __clone-Methode angepasst werden. Innerhalb dieser Methode zeigt die Pseudovariable $this bereits auf die Kopie des Originalobjektes, die mit den Instanzvariablen desselben initialisiert wurde.

Die Klasse Connection aus Beispiel 1.11 kapselt neben den Zugangsdaten für eine MySQL-Serververbindung auch eine Ressource, die eine bestehende Verbindung repräsentiert. Die definierte __clone-Methode baut nach dem Klonen eines Objektes der Klasse Connection eine neue Verbindung zur Datenbank auf und benutzt hierzu die aus dem Originalobjekt kopierten Verbindungsdaten.

Beispiel 1.11: Den Kopiervorgang eines Objektes anpassen

<?php
class Connection {
  private $connection;
  private $host;
  private $database;
  private $user;
  private $pass;
 
  public function __construct($host,$database,$user,$pass) {
    $this->connect($host, $database, $user, $pass);
  }
 
  public function __clone() {
    $this->connect();
  }
 
  public function
  connect($host='', $database='', $user='', $pass='') {
    if (!empty($host)) {
      $this->host = $host;
    }
 
    if (!empty($database)) {
      $this->database = $database;
    }
 
    if (!empty($user)) {
      $this->user = $user;
    }
 
    if (!empty($pass)) {
      $this->pass = $pass;
    }
 
    $this->connection = mysql_connect(
      $this->host,
      $this->user,
      $this->pass,
      TRUE
    );
 
    mysql_select_db($this->database, $this->connection);
  }
}
?>


Das Anpassen des Kopiervorgangs mit einer __clone-Methode ist ebenfalls notwendig, wenn das zu kopierende Objekt ein anderes Objekt aggregiert. Ohne eine Anpassung des Kopiervorgangs würde nämlich die entsprechende Instanzvariable der Kopie eine Referenz auf das vom Original aggregierte Objekt enthalten (Shallow Copy). Beispiel 1.12 zeigt eine __clone-Methode, die eine so genannte Deep Copy erzeugt. Hierbei wird das aggregierte Objekt kopiert, und nicht die Referenz auf dieses.

Beispiel 1.12: Implementieren von Deep-Copy mit __clone()

<?php
class Aggregat {
}
 
class Klasse {
  protected $aggregat;
 
  public function __construct() {
    $this->aggregat = new Aggregat;
  }
 
  public function __clone() {
    $this->aggregat = clone $this->aggregat;
  }
 
  public function aggregat() {
    return $this->aggregat;
  }
}
 
$original = new Klasse;
$kopie    = clone $original;
 
if ($original->aggregat() !== $kopie->aggregat()) {
  print 'Original und Kopie aggregieren nicht dasselbe Objekt.';
}
?>
Original und Kopie aggregieren nicht dasselbe Objekt.


Möchte man erreichen, dass nur Methoden des Objektes selbst dieses klonen dürfen, so ist die __clone-Methode als protected zu deklarieren. Soll das Klonen eines Objektes vollständig unterbunden werden, ist die __clone-Methode als final private zu deklarieren.