Aaron Fischer Ingenieur, Vater, Heimwerker, Problemlöser

13 July, 2007

Namespaces in PHP

Programmiersprachen

In 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 bis 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 drin bleiben. 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.