PHP

PHP & OOP - Das Registry Pattern (PHP Tutorial)

Tutorial erstellt von Andreas W. in PHP 5.x, letzte Änderung am 14.04.2011

Im Rahmen der Entwicklung einer größeren Applikation stößt ein Entwickler früher oder später auf das Problem, dass Objekte und Variablen immer wieder benötigt werden und somit eigentlich global verfügbar sein müssen.
Natürlich ist dies eigentlich ohne weiteres möglich, jedoch soll auch vermieden werden, ein Objekt oder eine Variable als global zu definieren oder ein Objekt unnötiger Weise mehrfach zu instanziieren. Das Registry Pattern bietet eine einfache Möglichkeit all diese Anforderungen unter einen Hut zu bringen.

Anforderungen an eine Registry


Tragen wir nachfolgend nochmal alle Anforderungen zusammen.

Eine Registry soll ...

  1. ... Variablen und Objekte verwalten, ...

  2. ... selbst global für den Programmierer verfügbar sein, ...

  3. ... bei der Vermeidung von vermehrten Instanziierungen helfen ...

  4. ... und dabei selbst nicht unnötig oft im Speicher gehalten werden.



Die Implementierung


Da die Registry Klasse Daten global zur Verfügung stellen soll, dabei jedoch eine vermehrte Instanziierung von in ihr gespeicherten Objekten vermeiden soll, ist es wichtig sicherzustellen, dass auch nur eine Instanz der Registry Klasse existieren kann.

Das Singleton Pattern ist für diesen Zweck hervorragend geeignet. Man verwaltet eine Instanz der jeweiligen Klasse in einer statischen Variablen, die zwangsweise auch nur über eine statische Methode zugreifbar ist. Den Konstruktor der Klasse sowie die clone() Methode deklariert man als private.

Code:

class Registry {
   private static $instance = null;

   public static function getInstance() {
      if(is_null($this->instance)) {
         $this->instance = new self();
      }

      return $this->instance;
   }

   private funtion __construct() {}

   private funtion __clone() {}
}


Da nun die Registry vor unnötiger Instanziierung geschützt ist, kann man sich nun um die Haltung der Daten kümmern. Dazu wird der Klasse ein Array und einige CRUD-Methoden (CRUD = Create, Read, Update and Delete) hinzugefügt.

Code:

class Registry {
   private $cache = array();

   ...

   public function set($offset, $value) {
      if(is_null($offset)) {
         $this->cache[] = $value;
      } else {
         $this->cache[$offset] = $value;
      }
   }

   public function get()($offset) {
      return isset($this->cache[$offset]) ? $this->cache[$offset] : null;
   }
}


Um den Zugriff auf die in der Registry gehaltenen Daten etwas komfortabler zu gestalten, lohnt es sich einige Interfaces der Standard PHP Library (SPL) zu implementieren.

Besonders interessant ist der Zugriff auf die Registry als Objekt, wie auf ein Array. Diese Möglichkeit bietet das ArrayAccess Interface, das die Implementierung folgender Methoden erfordert.

Code:

public boolean offsetExists ( mixed $offset );
public mixed offsetGet ( mixed $offset );
public void offsetSet ( mixed $offset , mixed $value );
public void offsetUnset ( mixed $offset );


Das sollte kein Problem darstellen, da wir in der Registry nun einmal auf einem Array arbeiten. Die fertigen Methoden sollten also wie folgt aussehen.

Code:

public function offsetSet($offset, $value) {
   if(is_null($offset)) {
      $this->cache[] = $value;
   } else {
      $this->cache[$offset] = $value;
   }
}

public function offsetExists($offset) {
   return isset($this->cache[$offset]);
}

public function offsetUnset($offset) {
   unset($this->cache[$offset]);
}

public function offsetGet($offset) {
   return isset($this->cache[$offset]) ? $this->cache[$offset] : null;
}


Es darf natürlich nicht vergessen werden auch den Kopf der Registry Klasse anzupassen.

Code:

class Registry implements ArrayAccess {
   ...
}


Da die Registry Klasse nun auch um Operationen erweitert wurde, die einen Zugriff wie auf ein Array ermöglichen und somit auch das Löschen von einzelnen Datensätzen ermöglicht wird, macht es Sinn, auch das Löschen aller Datensätze, d.h. das Bereinigen der Registry zu ermöglichen. Diese Aufgabe übernimmt die Methode clear().

Code:

public funtion clear() {
   $this->cache = array();
}


Da nun auch diese Aufgabe erledigt wurde, soll abschließend noch das Countable Interface der SPL eingepflegt werden, sodass ein Objekt der Klasse Registry mit der Funktion count() verwendet werden kann, um die Einträge in der Registry zu zählen.

Dazu muss zuerst der Kopf der Klasse wieder erweitert ...

Code:

class Registry implements ArrayAccess, Countable {
   ...
}


... und anschließend die Methode count() implementiert werden.

Code:

public function count() {
   return count($this->cache);
}


Die fertige Registry Klasse stellt damit eine komfortable Möglichkeit dar, Objekte und Daten zu verwalten und global zugreifbar zu machen. Sie verhindert zwar nicht das vermehrte Instanziieren von Objekten, hilft jedoch dabei dies zu vermeiden und da sie selbst das Singleton Pattern implementiert, kann sie selbst auf keinen Fall mehrfach erzeugt werden und ist global verfügbar.

Ein Beispiel aus der Praxis


Objekte und Daten, die sehr häufig in einer Applikation benötigt werden sind zumeist solche, die den Zugriff auf eine Ressource kapseln bzw. ermöglichen.

Eine Datenbank ist zum Beispiel eine solche Ressource. Die Kommunikation mit einer solchen erfolgt über einen Datenbank-Handler, der mit den Verbindungsdaten initialisiert wird. Solche Daten liegen zumeist in Konfigurationsdateien, die, wie im Tutorial PHP & OOP - Konfigurationsmanagement beschrieben, gelesen werden können.

Das nachfolgende Beispiel illustriert, wie sowohl das PHP Data Object (PDO), als auch der Konfigurations-Handler in einer Registry abgelegt werden können, sodass sie dann global verfügbar sind. Außerdem zeigt dieses Beispiel auch, wie dann auf diese Daten aus der Applikation zugegriffen werden kann.

Code:

<?php

   try {
      // Import all needed libraries.
      require_once('core/registry/Registry.php');
      require_once('core/config/IniConfiguration.php');

      // Create an Registry object, ...
      $registry = Registry::getInstance();
      
      // ... load the basic config and add it to the registry.
      $registry->set('config', new IniConfiguration('config.ini.php'));
      
      // Then load the database connection parameters, ...
      $db = $registry->get('config')->getSection('database');
      
      // ... create the pdo mysql string, ...
      $pdoString = "mysql:host=" . $db['host'] . ";dbname=" . $db['name'];
      
      // ... initialize the database connection object ...
      $pdo = new PDO($pdoString, $db['user'], $db['pwd']);
      
      // ... and add it to the registry too.
      $registry->set('pdo', $pdo);
   }
      
   catch(Exception $e) {
      echo $e->getMessage();
   }

?>


Die fertige Klasse


Eine bereits implementierte Klasse gibt es natürlich auch. Diese findet ihr als *.zip-Archiv im Bereich Skripte des Download-Archivs. Ich möchte darum bitten, an dieser Klasse nur unter Rücksprache etwas zu ändern und die eingefügten Kommentare und Versions-Hinweise nicht zu entfernen.

Hinweise zur Implementation, Erweiterungsvorschläge oder BugFixes sind natürlich gern gesehen und können, wie unter Fragen & Antworten beschrieben, an mich weitergegeben werden.

Fragen und Antworten


Fragen und Antworten findet ihr selbstverständlich bei uns im Forum. Ich möchte euch auch darum bitten, keine Fragen an mich persönlich zu senden aus dem einfachen Grund, dass die anderen Leser in diesem Fall nichts von den gegebenen Antworten haben. Zudem können euch im Forum auch viele andere Benutzer, die viel Ahnung haben, helfen. Natürlich freue ich mich über ein kurzes Feedback zu diesem Tutorial. Auch ein Link oder Blog-Post kann helfen. Ich bedanke mich für eure Aufmerksamkeit und hoffe, dass euch mein kurzer Exkurs gefallen hat.

Liebe Grüße

Andreas

http://www.avedo.net

Objekte und Variablen global in einer Applikation zu verwalten ist schwierig, wie das Registry Pattern helfen kann erklärt dieses Tutorial.


>> Allgemeine Fragen oder Probleme mit dem Tutorial? Hier gehts zum Forum!

Impressum / Datenschutzerklärung          © der-Webdesigner.net 2002 - 2011           top ▲