Automatisches Nachladen von Klassen mit PHP
PHP bietet seit der Version 5 die Möglichkeit, Klassen automatisch bei Bedarf nachzuladen.
Einfaches Laden über __autoload
Klassen können in PHP seit Version 5 dynamisch nachgeladen werden. Darunter ist zu verstehen, dass PHP eine benutzerdefinierte Funktion aufruft, falls eine bis dahin unbekannte Klasse angefordert wird. Beispiel:
$a = new UnbekannteKlasse ();
UnbekannteKlasse
sei in dem Moment noch nicht definiert. Im Normalfall wird PHP automatisch eine Fehlermeldung "Klasse nicht gefunden" ausgeben und sich beenden. Definiert man jedoch eine Funktion namens __autoload
(sie beginnt mit zwei Unterstrichen), so wird zuerst diese aufgerufen. Ihr wird genau ein Parameter übergeben: Der Name der Klasse, die nicht gefunden wurde und nachgeladen werden soll. Die Funktion kann nun an Hand des Klassennamens versuchen, die passende PHP-Datei einzubinden (per include
), damit die Klasse nach Beendigung der Funktion definiert ist. Sollte die Funktion keine Datei zu der angegebenen Klasse finden, d.h. die Klasse existiert nach Aufruf der Funktion immer noch nicht, gibt PHP die bekannte Fehlermeldung aus.
Ein einfaches Beispiel für eine derartige Funktion wäre:
function __autoload ($klasse) {
// die bösesten zeichen in klassennamen mal sicherheitshalber verbieten
if (strpos ($klasse, '.') !== false || strpos ($klasse, '/') !== false
|| strpos ($klasse, '\\') !== false || strpos ($klasse, ':') !== false) {
return;
}
if (file_exists ($klasse.'.php')) {
include_once $klasse.'.php';
}
}
Die Funktion versucht nun eine Datei namens Klassenname.php zu finden und diese dann einzubinden, falls sie existiert. Einzige Besonderheit hier ist die Überprüfung auf schädliche Zeichen: Im Normalfall sind diese Zeichen in Klassennamen in PHP sowieso nicht erlaubt, allerdings reicht call_user_func
diese Zeichen unter Umständen direkt an __autoload
durch. Damit wäre es unter Umständen möglich, dass fremde Inhalte per include
eingebunden werden können. Dies wird durch diese Abfrage verhindert.
Verwendet man __autoload
, so kann man auf lange Include-Listen am Anfang von PHP-Dateien verzichten, man muss nur noch die Datei einbinden, die __autoload
definiert.
Der spl_autoload_register
-Mechanismus
Zusätzlich bietet PHP im Rahmen der SPL (Standard PHP Library) die Funktion spl_autoload_register
an. Diese ermöglicht es, den normalen Nachlademechanismus zu ersetzen. Das heißt: Sobald spl_autoload_register
einmal aufgerufen wurde, ist der normale Nachlademechanismus außer Kraft gesetzt.
Die Funktion spl_autoload_register
akzeptiert einen Parameter: Den Namen einer Funktion, die versuchen soll, eine Klasse automatisch nachzuladen. Diese wird dann an Stelle von __autoload
verwendet. Falls der Parameter nicht angegeben wird, wird die Funktion spl_autoload
angenommen, die versucht, die Klasse kleingeschrieben als Dateinamen mit .php oder .inc als Endung einzubinden.
Dies kann aus zwei Gründen interessant sein:
-
Man möchte keine eigene Funktion programmieren, weil einem die Funktionalität, die
spl_autoload
bietet, ausreicht. In dem Fall reicht es einfach, folgenen Aufruf zu tätigen:spl_autoload_register ();
-
Man möchte mehrere Funktionen nutzen, die Klassen automatisch nachladen sollen. Dann kann man einfach
spl_autoload_register
mehrfach aufrufen und die dort angegebenen Funktionen werden der Reihe nach aufgerufen, bis die Klasse gefunden wurde:spl_autoload_register ('nachlade_funktion_1');
spl_autoload_register ('nachlade_funktion_2');
Hier sei noch angemerkt, dass ein Aufruf von spl_autoload_register ('__autoload');
dafür sorgt, dass wieder die klassische __autoload
-Methode aufgerufen wird, auch wenn zum Beispiel noch andere Funktionen zusätzlich definiert sind.
Anwendung in Klassenbibliotheken
Dies ist für Autoren von Klassenbibliotheken, die aus mehreren Klassen bestehen, nun besonders interessant. Vorher mussten entweder die Entwickler einer Klassenbibliothek selbst dafür sorgen, dass jede Datei die korrekten anderen Dateien einbund (wobei sie dort dann auf Dinge wie den include_path
achten mussten) oder sie wälzten die Verantwortung auf die Nutzer der Klassenbibliothek ab.
Nun kann eine Klassenbibliothek nämlich eine Funktion anbieten, die alle relevanten Klassen dieser Bibliothek automatisch nachlädt. Jemand, der die Klassenbibliothek (oder Teile davon) nutzen will, muss nur noch die Datei einbinden, die diese Funktion enthält und sie dann entweder in seiner eigenen __autoload
-Funktion aufrufen oder per spl_autoload_register
zu den registrierten Nachladefunktionen hinzufügen.
Folgendes Beispiel soll für eine Klassenbibliothek gelten, deren Präfix SELFHTML
ist, d.h. jede Klasse fängt mit diesen acht Zeichen an. Im Hauptverzeichnis der Klassenbibliothek liegt nun eine Datei Autoloader.php
, die folgenden Inhalt besitzt:
class SELFHTMLAutoloader {
private static $basisPfad = null;
public static function autoload ($klasse) {
if (self::$basisPfad === null) self::$basisPfad = dirname (__FILE__);
if (substr ($klasse, 0, 8) !== "SELFHTML") return;
if (strpos ($klasse, '.') !== false || strpos ($klasse, '/') !== false
|| strpos ($klasse, '\\') !== false || strpos ($klasse, ':') !== false) {
return;
}
$teile = preg_split ('/(?<=.)(?=\p{Lu}\P{Lu})|(?<=\P{Lu})(?=\p{Lu})/U', substr ($klasse, 8));
$pfad = self::$basisPfad . DIRECTORY_SEPARATOR .
join (DIRECTORY_SEPARATOR, $teile) . '.php';
if (!file_exists ($pfad)) return;
include_once $pfad;
}
}
Der Code macht nun folgendes:
- Zuerst wird der Basis-Pfad der Klassenbibliothek ausfindig gemacht. Da die Datei
Autoloader.php
direkt darin liegt, ist der Basis-Pfad natürlich das Verzeichnis, in dem sich diese Datei befindet, alsodirname (__FILE__)
. Der Pfad wird zwischengespeichert, um bei weiteren Aufrufen Zeit zu sparen. - Nun wird überprüft, ob die Klasse zur Klassenbibliothek gehört, in diesem Fall wird dies daran erkannt, ob die Klasse mit
SELFHTML
anfängt. - Schließlich werden hier die gleichen Überprüfungen auf schädliche Zeichen durchgeführt, wie oben.
- Nun wird der Name der Klasse aufgeteilt in mehrere Elemente. Hier wird angenommen, dass die Klasse in CamelCase vorliegt, das heißt, dass in dem Klassennamen Wörter aneinandergereiht werden, deren erster Buchstabe immer großgeschrieben wird. Als Beispiel: TestKlasse. Der Ausdruck würde dies in zwei Teile "Test" und "Klasse" aufteilen.
- Die Teile werden nun wieder zusammengefügt mit Hilfe der Konstante
DIRECTORY_SEPARATOR
, das ist der Verzeichnistrenner unter dem jeweiligen Betriebssystem, unter Windows also\
, unter Linux oder Mac OS X/
. Zudem wird die Endung .php angehängt und der vorher bestimmte Basispfad berücksichtigt. Aus SELFHTMLTestKlasse wird also /Pfad/zur/Klassenbibliothek/Test/Klasse.php. - Falls diese Datei existiert, wird diese eingebunden.
Selbstverständlich ist die genaue Art, wie hier die Klasse nachgeladen wird, nur ein Beispiel. Falls die Autoren der Klassenbibliothek andere Konventionen als CamelCase bevorzugen, kann eine anders geschriebene Funktion dies natürlich berücksichtigen.
Will nun ein anderer Entwickler die Klassenbibliothek verwenden, so kann er einfach folgenden Code nutzen:
require_once '/Pfad/zur/Klassenbibliothek/Autoloader.php';
spl_autoload_register (array ('SELFHTMLAutoloader', 'autoload'));
Selbstverständlich wäre auch möglich, in einer eigenen __autoload
-Funktion diese Funktion aufzurufen:
require_once '/Pfad/zur/Klassenbibliothek/Autoloader.php';
function __autoload ($klasse) {
// ...
SELFHTMLAutoloader::autoload ($klasse);
// ...
}
Fazit
Mit dem automatischen Nachladen von Klassen ermöglicht es PHP 5 Programmierern, sehr lange Listen von include
-Anweisungen zu vermeiden. Zudem wird das Einbinden von Klassenbibliotheken, die sich an das hier vorgestellte Schema halten, stark vereinfacht: Es müssen weder Laufzeitkonstanten gesetzt werden noch muss der include_path
angepasst werden.