smart | Webentwicklung
Alles rund um HTML5, PHP, WordPress & Co.

PHP: Klassen nachladen via Namespaces & Autoloader

15. November 2012
Stephan
PHP: Klassen automatisch nachladen mit Autoloader & Namespaces

In diesem Artikel möchte ich euch zeigen, wie ihr in PHP mithilfe der SPL (Standard PHP Library) eine eigene kleine Autoloader-Klasse implementieren könnt.

Eine Autoloader-Klasse dient dazu Klassen zu laden, die zur Laufzeit nicht gefunden wurden. Das hat den Vorteil, dass ihr nicht in jeder Datei jede benötigte Klasse, um genauer zu sein, die entsprechende Datei, per include oder require laden müsst.

Die Autoloader-Klasse, die euch hier vorstelle, verwendet zudem beim Laden von Klassen deren Namespaces, um den richtigen Dateipfad zu ermitteln.

Beispielhaftes Projektverzeichnis

In einem PHP-Projekt, an dem ich zurzeit arbeite, sieht mein Projektverzeichnis wie folgt aus:

PHP Autoloader: Beispiel Projektverzeichnis

Autoloader implementieren

Im Verzeichnis core/ legen wir eine Datei namens Autoloader.php an und fügen den folgenden Code ein:

namespace MyApp\core;

class Autoloader
{
    private $namespace;

    public function __construct($namespace = null)
    {
	    $this->namespace = $namespace;
    }

    public function register()
    {
	    spl_autoload_register(array($this, 'loadClass'));
    }

    public function loadClass($className)
    {
	    if($this->namespace !== null)
	    {
	    	$className = str_replace($this->namespace . '\\', '', $className);
	    }

        $className = str_replace('\\', DIRECTORY_SEPARATOR, $className);

	    $file = ROOT_PATH . $className. '.php';

	    if(file_exists($file))
	    {
	        require_once $file;
	    }
    }
}

Dem Konstruktor übergeben wir den Hauptnamespace des Projekts und speichern diesen in der namespace-Eigenschaft. In unserem Fall wäre der Hauptnamespace MyApp.

Die Methode register dient dazu, um unseren Autoloader beim SPL-Autoloader zu registrieren, so dass dieser unseren Autoloader mit aufruft. Hierfür übergeben wir der spl_autoload_register-Funktion ein Array. Das Array enthält als ersten Parameter eine Referenz auf unsere Autoloader-Instanz. Der zweite Parameter gibt an, welche Methode der Autoloader-Klasse aufgerufen werden soll.

Die loadClass-Methode ist schließlich die eigentliche Methode, die unsere Klassen lädt. Wie ihr seht, wird der Methode dafür der Parameter $className übergeben, welcher den vollqualifizierenden Klassennamen (also inklusive Namespace) der zu ladenen Klasse enhält.

Als erstes wird geprüft, ob der Hauptnamespace gesetzt ist. Wenn das der Fall ist, wird dieser aus $className gelöscht. Anschließend ersetzen wir alle Backslashes \ mit einem Verzeichnis-Separator der vom verwendeten System verwendet wird. Hierfür gibt es extra die Konstante DIRECTORY_SEPARATOR.

Danach speichern wir den Pfad zur Datei, die unsere gewünschte Klasse enthält in der Variablen $file.

Es sei darauf hingewiesen, dass der Klassenname mit dem jeweiligen Dateinamen übereinstimmt. In der Datei FrontController befindet sich also die Klasse FrontController.
Die Namespaces spiegeln sich wiederum in der Projektstruktur wieder. Die FrontController-Datei befindet sich im MyApp/core/-Verzeichnis. Analog dazu ist die FrontController-Klasse im Namespace \MyApp\core deklariert. Der vollqualifizierende Klassenname lautet also \MyApp\core\FrontController.

Abschließend laden wir die Datei, wenn sie existiert. Falls sie nicht existiert, könntet ihr auch noch eine Exception werfen.

Boostrap – Projektpfad ermitteln, Autoloader instanziieren

In der loadClass-Methode der Autoloader-Klasse befindet sich die Konstante ROOT_PATH. Diese habe ich in meinem Projekt in der bootstrap.php im config-Verzeichnis definiert. Außerdem instanziiere ich hier den Autoloader:

use \MyApp\core\Autoloader;

define( 'ROOT_PATH', dirname( dirname( __FILE__ ) ) . '/' );
define( 'APP_PATH', ROOT_PATH . 'app/' );
define( 'CONFIG_PATH', ROOT_PATH . 'config/' );
define( 'CORE_PATH', ROOT_PATH . 'core/' );
define( 'DB_PATH', ROOT_PATH . 'db/' );

require_once CORE_PATH . 'Autoloader.php';

$autoloader = new Autoloader('MyApp');
$autoloader->register();

Klassen mittels Autoloader laden

Die bootstrap.php könnt ihr nun, dort wo sich der Einstiegpunkt eurer Applikation befindet, einbinden. Im gängigen Fall ist das die index.php. In meinem Fall sieht sie folgt aus:

use \MyApp\core\HttpRequest,
\MyApp\core\HttpResponse,
\MyApp\core\Router,
\MyApp\core\Dispatcher,
\MyApp\core\FrontController;

require_once 'config/bootstrap.php';

$httpRequest = new HttpRequest();
$httpResponse = new HttpResponse();
$router = new Router($httpRequest);
$dispatcher = new Dispatcher();

$frontController = new FrontController($httpRequest, $httpResponse, $router, $dispatcher);
$frontController->run();

Wir müssen also nur die bootstrap.php-Datei per require laden. Anschließend werden alle Klassen mittels unseres Autoloaders geladen, sobald sie benötigt werden.

Fazit

Ein Autoloader erleichtert einem Entwickler bei größeren Projekten viel Aufwand. Es muss also nicht in jeder Datei manuell andere Dateien bzw. Klassen eingebunden werden, sondern der Autoloader macht das ganz automatisch für uns.

Falls ihr Fragen oder Feedback zum Autoloading in PHP habt, dann hinterlasst mir doch einfach ein Kommentar.

Kommentare  
13 Kommentare vorhanden
1 Chris schrieb am 22. März 2013 um 10:34 Uhr

Hallo Stephan!

Erstmal super Artikel! 🙂

Da ich mich im Moment mit MVC beschäftige, wollte ich dich fragen ob du mir mal alle Dateien im obigen Projektverzeichnis zur Verfügung stellen könntest, um den Zusammenhang aller Klassen zu verstehen.

Wäre echt super wenn du mir die vieleicht in einer Zip Datei zuschicken könntest!

Grüsse
Chris

2 Stephan L. schrieb am 22. März 2013 um 17:54 Uhr

Hallo Chris,

kein Problem, habe ich dir gerade per E-Mail gesendet.

Grüße

Stephan

3 Sieglinde schrieb am 28. Juli 2013 um 21:28 Uhr

Hallo Chris, toller Artikel!
Leider bekomme ich die „autoload“ Funktion nicht zum Laufen. Mit dem üblichen „require_once“ der einzelnen Files habe ich kein Problem, lade ich diese per „autoload“ wie in deinem Tutorial, endet die Sache mit einem:

Fatal error: Class ‚MyProject\Admin\Core\Classes\Auth‘ not found in…

Ist in deinem Beispiel (Autoload.php) die die Angabe

$file = ROOT_PATH . $className. ‚.php‘;

korrekt? Sollte dort nicht eher „CORE_PATH“ stehen?
——–^^^^^^^^^

4 Stephan L. schrieb am 29. Juli 2013 um 08:47 Uhr

Hallo Sieglinde,

die Angabe mit ROOT_PATH ist korrekt, damit alle Klassen und nicht nur die im CORE_PATH vom Autoloader richtig geladen werden können.

Stimmen deine verwendeten Namespaces denn auch mit der Verzeichnisstruktur überein?

Grüße

Stephan

5 Sieglinde schrieb am 29. Juli 2013 um 13:06 Uhr

Hallo Srephan!

>> Stimmen deine verwendeten Namespaces
>> denn auch mit der Verzeichnisstruktur
>> überein?

Danke! Meine Verzecinisstruktur liegt (beginnt) direkt in der Document-Root. Der Hauptnamespace ist also „\“. Jetzt funktioniert
das Laden.

Danke, Sieglinde.

6 Andi schrieb am 22. Juli 2014 um 19:03 Uhr

Hi, du scheinst über enormes Fachwissen zu verfügen. Ich würde gerne sehen, wie du deine Architektur im tieferen Sinne so gestaltet hast. Könntest du mir vllt ebenfalls ein ZIP-File mit den oben dargestellten Dateien schicken; das würde mich brennend interessieren.
Viele Grüße.

7 Lenny69 schrieb am 10. Februar 2015 um 03:28 Uhr

Hi, danke für den super Artikel. Ich fänd’s super, wenn du mir auch dein Projekt als Zip zukommen lassen könntest 🙂

8 Eugen schrieb am 8. Juni 2015 um 17:00 Uhr

Ich versuche mich auch gerade an den Namespaces 🙂 wäre es möglich deine Sourcen per E-Mail zu bekommen? Damit ich das gesamte Konzept verstehen kann.

9 Merlin Christen schrieb am 19. Juli 2015 um 13:12 Uhr

Hallo Stephan,

könntest du mir den obigen (MVC) Projektordner bitte auch schicken ?!

Vielen Dank im voraus =)

Merlin

10 Daniel schrieb am 21. Juli 2015 um 16:14 Uhr

Hallo Stephan,

zunächst bin ich sehr erfreut über dein Artikel die du hier super schön mit Erläuterung Veröffentlicht hast.

Da ich mich momentan mit MVC und Namespace beschäftigte und versuche das zu lernen, würde ich mich freuen, wenn du mir eventuell bei 1-2 Fragen helfen könntest.
Denn bei mir funktioniert das nicht so ganz und bekomme die Fehlermeldung, dass die Klasse nicht gefunden werden kann etc.

Wäre es denn möglich, dass du mir alle obigen Daten, gezippt per E-Mail zuschicken könntest, um mir das mit dem MVC und Namespace genauer analysieren zu können?

Wäre dir da echt sehr Dankbar und erfreut darüber.

Mit freundlichen Grüßen
Daniel

11 Rene schrieb am 27. Oktober 2015 um 09:01 Uhr

Zuerst einmal danke für deinen hervorragenden Artikel.

Mich würde jedoch das Zusammenspiel zwischen MVC und namespace interessieren.

Wäre es möglich, das du mir alle Dateien von Oben zur verfügung stellen könntest??

Danke schon mal im Voraus.

Gruß Rene

12 Mike schrieb am 20. Dezember 2015 um 16:23 Uhr

Super Artikel! Auch wenn es schon länger her ist, aber hast Du noch dieses Projekt und könntest es mir zuschicken?
Bin gerade dabei APP-Entwicklung mit MVC zu lernen.
Vielen Dank
Mike

13 Laura schrieb am 8. Februar 2016 um 18:36 Uhr

Hallo Stephan,

super Tutorial :). Das Tutorial ist ja nun schon etwas älter und daher wollte ich mal nachfragen, ob du eventuell eine Fortsetzung zum Thema Autoloading und PSR-4 machen könntest?

P.S. Ich würde mich ebenfalls über die Zusendung der Projektdateien deines Beispielprojektes freuen :).

Liebe Grüße
Laura

0 Trackbacks/Pingbacks vorhanden
Du bist herzlich eingeladen auch ein Kommentar zu hinterlassen!
Kommentar schreiben

Vielen Dank für dein Kommentar!