W3docs

PHP Namespaces verstehen

PHP Namespaces kapseln Klassen, Funktionen und Konstanten in einer logischen Struktur und verhindern so Namenskonflikte.

Ein Namespace ist eine Möglichkeit, verwandte Klassen, Interfaces, Funktionen und Konstanten unter einem einzigen logischen Namen zu gruppieren. Stellen Sie sich das wie Ordner auf Ihrer Festplatte vor: Zwei Dateien namens index.php können nebeneinander existieren, solange sie sich in unterschiedlichen Ordnern befinden. Auf die gleiche Weise können zwei Klassen namens User nebeneinander existieren, solange sie sich in unterschiedlichen Namespaces befinden.

Ohne Namespaces lebt jeder Name in einem gemeinsamen globalen Raum. Sobald Ihr Projekt und eine Drittanbieter-Bibliothek beide eine Klasse namens Logger oder Router definieren, wirft PHP einen fatalen Cannot declare class-Fehler. Namespaces sind die Standardlösung für dieses Problem und bilden die Grundlage des Composer-Autoloadings (dem PSR-4-Standard), das von praktisch jedem modernen PHP-Paket verwendet wird.

Warum Namespaces wichtig sind

  • Namenskonflikte vermeiden. Zwei Codeabschnitte können denselben Klassen- oder Funktionsnamen verwenden, solange sie in unterschiedlichen Namespaces liegen, sodass Ihr Code nie mit dem Code einer Bibliothek kollidiert.
  • Große Codebasen organisieren. Namespaces spiegeln Ihre Ordnerstruktur wider und machen es deutlich, wo eine Klasse zu finden ist (App\Service\Mailer befindet sich in app/Service/Mailer.php).
  • Autoloading ermöglichen. PSR-4 ordnet ein Namespace-Präfix einem Verzeichnis zu, sodass Composer Klassen bei Bedarf laden kann, ohne manuelle require-Anweisungen.

Einen Namespace definieren

Deklarieren Sie einen Namespace mit dem Schlüsselwort namespace. Es muss die allererste Anweisung in der Datei sein (nur eine declare(strict_types=1)-Zeile darf davor stehen). Namespace-Namen verwenden einen Backslash (\) zur Trennung der Ebenen:

<?php
namespace App\Service;

class Mailer
{
    public function send(string $to): string
    {
        return "Mail sent to {$to}";
    }
}

Alles, was unterhalb der namespace-Zeile deklariert wird — die Klasse Mailer — lebt nun in App\Service. Ihr vollständig qualifizierter Name lautet App\Service\Mailer.

Auf Namespace-Elemente verweisen

Es gibt drei Möglichkeiten, auf einen Namen aus einem anderen Namespace zu verweisen.

Ein vollständig qualifizierter Name beginnt mit einem führenden \ und benennt das Element vom globalen Wurzelverzeichnis aus — er ist überall eindeutig:

<?php
$mailer = new \App\Service\Mailer();

Ein qualifizierter Name ist relativ zum aktuellen Namespace, sodass Service\Mailer innerhalb des Namespace App zu App\Service\Mailer aufgelöst wird. Ein Name ohne Backslash ist unqualifiziert und wird zunächst im aktuellen Namespace gesucht.

Importieren mit use

Den vollständigen Pfad jedes Mal zu schreiben ist umständlich. Das Schlüsselwort use importiert einen Namen in die aktuelle Datei, sodass Sie ihn mit seinem Kurznamen referenzieren können:

<?php
use App\Service\Mailer;

$mailer = new Mailer();   // resolves to App\Service\Mailer

Alias mit as

Wenn zwei importierte Klassen denselben Kurznamen haben, geben Sie einer einen Alias mit as, um sie zu unterscheiden:

<?php
use App\Service\Mailer;
use Vendor\Mail\Mailer as VendorMailer;

$a = new Mailer();        // App\Service\Mailer
$b = new VendorMailer();  // Vendor\Mail\Mailer

Funktionen und Konstanten importieren

use importiert standardmäßig Klassen. Um eine Funktion oder eine Konstante zu importieren, fügen Sie das Schlüsselwort function oder const hinzu:

<?php
use function App\Helpers\format_price;
use const App\Config\TAX_RATE;

Achtung: Eingebaute Funktionen benötigen einen führenden Backslash

Innerhalb eines Namespace wird ein unqualifizierter Funktions- oder Klassenname zuerst gegen den aktuellen Namespace aufgelöst. Bei eingebauten Funktionen fällt PHP automatisch auf die globale Version zurück, aber bei eingebauten Klassen tut es das nicht. Daher erfordert die Referenzierung von Kernklassen wie Exception, DateTime oder PDO einen führenden Backslash (oder eine use-Anweisung):

<?php
namespace App\Service;

// Wrong: PHP looks for App\Service\Exception, which doesn't exist.
// throw new Exception('boom');

// Right: leading backslash points to the global class.
throw new \Exception('boom');

Ein gebräuchliches, lesbares Muster ist es, die Kernklasse am Anfang der Datei zu importieren:

<?php
namespace App\Service;

use Exception;

throw new Exception('boom');   // now the short name works

Ein vollständiges Beispiel

Dieses einzelne, ausführbare Skript definiert zwei Namespaces und verwendet beide — es zeigt, wie derselbe Kurzklassenname an zwei Stellen ohne Konflikte existieren kann:

<?php
namespace App\Billing {
    class Invoice
    {
        public function label(): string
        {
            return 'Billing invoice';
        }
    }
}

namespace App\Shipping {
    class Invoice
    {
        public function label(): string
        {
            return 'Shipping invoice';
        }
    }
}

namespace Main {
    use App\Billing\Invoice;
    use App\Shipping\Invoice as ShippingInvoice;

    $billing  = new Invoice();
    $shipping = new ShippingInvoice();

    echo $billing->label() . "\n";
    echo $shipping->label() . "\n";
}

Ausgabe:

Billing invoice
Shipping invoice

Die geschweifte namespace Foo { ... }-Syntax wird nur verwendet, um mehrere Namespaces in einer Datei unterzubringen (praktisch für ein eigenständiges Beispiel). In echten Projekten legt man einen Namespace pro Datei an und verlässt sich auf Composer-Autoloading.

Namespaces und Autoloading (PSR-4)

In der Praxis schreiben Sie die Namespace-Grenzen selten manuell für jede Datei — Composer übernimmt die Verdrahtung. Eine PSR-4-Zuordnung in composer.json verknüpft ein Namespace-Präfix mit einem Ordner:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

Mit dieser Konfiguration wird die Klasse App\Service\Mailer automatisch aus src/Service/Mailer.php geladen, wenn Sie sie zum ersten Mal referenzieren — ohne manuelles include oder require.

Zusammenfassung

  • Ein Namespace gruppiert Klassen, Interfaces, Funktionen und Konstanten, um Namenskonflikte zu verhindern und Code zu organisieren.
  • Deklarieren Sie ihn mit namespace App\Service; als erste Anweisung in der Datei.
  • Referenzieren Sie Elemente über ihren vollständig qualifizierten Namen (\App\Service\Mailer) oder, häufiger, importieren Sie sie mit use und verwenden Sie den Kurznamen.
  • Vergeben Sie Aliase für kollidierende Namen mit as und denken Sie daran, globale Klassen wie \Exception innerhalb eines Namespace mit einem führenden Backslash zu versehen.
  • PSR-4-Autoloading ordnet ein Namespace-Präfix einem Verzeichnis zu — so wird jedes Composer-Paket geladen.

Übung

Übung
Was sind die Zwecke von PHP Namespaces?
Was sind die Zwecke von PHP Namespaces?
Was this page helpful?