In PHP sind wir bereits von vielen Plugins und Modulen umgeben, die unsere Probleme vollständig lösen und eigentlich gar keiner Erweiterung bedürfen. Da aber deren Entwickler natürlich nicht unsere Interfaces kennen und es auch keine allgemein gültigen Spezifikationen dafür gibt, müssen sie noch vereinheitlicht werden – dazu wird ein sogenannter Adapter verwendet.
Caching als Beispiel
Wenn es um Caching geht, denken die meisten wohl recht schnell daran einen Adapter zu erstellen – oft ohne das so explizit zu wissen. Jeder erkennt aber instinktiv das Problem, wenn man Memcache und XCache nebeneinander hält. Während Memcache wunderbar objektorientiert ist, kommt XCache noch mit Funktionen daher.
Dass xcache_get
und Memcache::get
nicht so richtig unter einen Hut gehen, ist recht offensichtlich.
Adapter erhält die Wartbarkeit
Um zukünftig das Caching auch mal austauschen zu können – wir denken da nur an den Wechsel von APC zu XCache, müssen alle Module dem selben Interface gehorchen.
Ein Interface für alle
Zu einem Adapter gehört normalerweise auch ein Interface, hier eines für unseren Cache.
1 2 3 4 5 |
interface IsCache { public function get($key); public function save($key, $value, $ttl = null); } |
Adapter für die verschiedenen Module
Für den XCache sähe der Adapter dann so aus:
1 2 3 4 5 6 7 8 9 10 11 12 |
class XCache implements IsCache { public function get($key) { return xcache_get($key); } public function save($key, $value, $ttl = null) { xcache_set($key, $value, (int)$ttl); } } |
Und für Memcache so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class MyMemcache implements IsCache { private $cache; public function __construct() { $this->cache = new Memcache(); $this->cache->addserver('localhost'); } public function get($key) { return $this->cache->get($key); } public function save($key, $value, $ttl = null) { $this->cache->set($key, $value, null, (int)$ttl); } } |
Memcache verlangt, dass ein oder mehrere Server definiert werden. Das kann hier ein Konstruktor erledigen, ohne dass der Anwender der Cache-Klassen davon behelligt wird.
Verwendung
In der Anwendung merkt man dann nichts mehr davon, welcher Cache tatsächlich verwendet wird – es wird lediglich der entsprechende Service abgerufen, gegen obiges Interface geprüft (falls wir kleinlich sein wollen) und verwendet.
1 2 3 4 5 6 7 8 9 10 11 12 |
class IndexController { public function indexAction() { $cache = DI::get('cache'); if ($cache instanceof IsCache) { $value = $cache->get('some_data'); // ... } } } |