Namespaces in PHP
vom 14. July 2007In den "Enterprise"-Programmiersprachen sind Namensräume bereits seit längerem verfügbar. In Java werden diese mit dem Befehl "package" definiert und mit "import" verwendet, in Ruby spricht man hier von "Modulen". In PHP gibt es dieses Konstrukt leider immer noch nicht, was in größeren Projekten zu langen Klassennamen und Prefixen führt, um keine Namenskonflikte entstehen zu lassen.
Vor ca. einem Jahr waren Namensräume auf der internals-Mailingliste ein heißes Thema, wurde aber wieder fallen gelassen, da niemand eine anständige Implementierung hinbekommen hat. am 4.7.07 hat Dmitry Stogov das Thema wieder aufgegriffen und einen Patch incl. Tests für eine funktionierende Implementierung zum Testen veröffentlicht. In der Diskussion ging es bist jetzt hauptsächlich um das Thema: Soll es in einer Datei nur einen oder mehrere Namensräume geben? Ich persönlich wäre ja für ersteres.
Ich konnte es nicht lassen und hab versucht, den Patch einmal in einen frischen Snapshot einzuspielen. Beim Patchen wurde mir allerdings mitgeteilt, das die Änderungen bereits im Code sind. Also nur noch schnell compilieren und das Testen kann beginnen:
a_c.php
namespace A::C;
class a {
function __construct() {
echo "Namespace: " . __NAMESPACE__ . "n";
}
}
function a() {
echo "Namespace: " . __NAMESPACE__ . "n";
}
Die Datei repräsentiert den Namensraum "A::C", in dem die Klasse a und die Funktion a() definiert ist.
a_b.php
namespace A::B;
require 'a_c.php';
import A::C as Alias;
function a() {
echo "Namespace: " . __NAMESPACE__ . "n";
}
new Alias::a;
Alias::a();
A::C::a();
a();
In der zweiten Datei wird der Namensraum "A::B" definiert und die Datei "a_c.php" eingebunden. Der Namensraum "A::C" wird importiert und unter dem Alias-Namen "Alias" geführt. Auf diesen kann dann äquivalent zu "A::C" zugegriffen werden. Im Namensraum "A::B" wird noch einmal die Funktion a() definiert, um den Effekt zu demonstrieren.
Die neue Instanz aus "Alias::a" stammt aus dem "A::C" Namensraum, welches die Ausgabe "Namespace: A::C" bestätigt. Der Aufruf "Alias::a()" wird intern (wie die Zeile darüber) auf "A::B::a()" gemapped und vom entsprechenden Namensraum ausgeführt. Genauso die nächste Zeile. Der Aufruf "a()" gibt nun "Namespace: A::B" aus, da sie im Namensraum "A::B" definiert ist.
Die gleichen Namensräume können auch in mehreren Dateien verwendet werden. Also wenn ich in beiden Dateien den Namensraum "A::B" verwendet hätte, gäbe es bei dem Aufruf "a()" einen Namenskonflikt.
Fatal error: Cannot redeclare a::b::a()
Alles in Allem funktioniert die Sache schon recht gut. Die Fehlerausgabe ist noch etwas dürftig und missverständlich, aber das wird sich vermutlich schnell richten. Ich freue mich auf jeden Fall schon auf ein offizielles (pre) Release und hoffe, das die Namespaces drinbleiben. Und noch eine erfreuliche Nachricht: Ab dem 1.1.2008 ist PHP4 offiziell tot. Mal sehen ob das die großen Hoster bis dahin gebacken kriegen.