Autoloader und Namespace

bofh1337

Erfahrenes Mitglied
Ich bin gerade dabei, einen Autoloader für mein Projekt zu bauen und frage mich, ob es Sinnvoll ist, den Pfad der benötigten Klasse anhand des Namespace zu ermitteln (wie es 10000 Beispiele im Net gibt).

Meiner Meinung nach sollte der Namespace nichts mit dem Pfad zu tun haben und die Klassen auf andere Wege gefunden werden, andererseits macht es auch keinen Sinn, den Namespace "root\html\includes" beim Pfad "libraries/environment" zu verwenden.

Wie seht ihr das? Nutzt ihr den Namespace gemäß der Ordnerstruktur oder habt ihr euer eigenes System darin?
 
Ich nutze nahezu immer PSR-0 beziehungsweise PSR-4, was im Grunde bedeutet: Ein Namespace (oder Sub-Namespace) ist an ein beliebiges Verzeichnis gekoppelt, und die Klassen (oder Sub-Namespaces) darin folgen dann einem festen 1:1-Mapping von Sub-Namespaces/Klassennamen auf die Verzeichnisstruktur.

- http://www.php-fig.org/psr/psr-0/
- http://www.php-fig.org/psr/psr-4/

Du könntest also zum Beispiel eine Klasse Foo\Bar\Baz\Blub haben, die in ./classes/Baz/Blub.php liegt, und im Autoloader den Namespace-Teil Foo\Bar nach ./classes mappen.

Ich würde einen Autoloader heutzutage nicht mehr selbst schreiben, ich würde empfehlen, dazu Composer zu nutzen.

- https://getcomposer.org/

Beispiel für eine Projektstruktur:

Code:
.
|-- src
|   |-- AbstractCRC.php
|   |-- CRC16CCITT.php
|   |-- CRC16DNP.php
|   |-- CRC16Modbus.php
|   |-- CRC16.php
|   |-- CRC16XModem.php
|   |-- CRC1.php
|   `-- CRCInterface.php
|-- composer.json
`-- test.php

In test.php soll nun ein Autoloader für die Klassen aus ./src genutzt werden können (die liegen alle in namespace mermshaus\CRC;).

Dazu schreibst du in composer.json:

Code:
{
    "autoload": {
        "psr-4": {
            "mermshaus\\CRC\\": "src"
        }
    }
}

Dann rufst du Composer im Projektverzeichnis auf:

Code:
$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Generating autoload files

Das erstellt ein ./vendor-Verzeichnis:

Code:
.
|-- src
|   |-- AbstractCRC.php
|   |-- CRC16CCITT.php
|   |-- CRC16DNP.php
|   |-- CRC16Modbus.php
|   |-- CRC16.php
|   |-- CRC16XModem.php
|   |-- CRC1.php
|   `-- CRCInterface.php
|-- composer.json
|-- test.php
`-- vendor
    |-- autoload.php
    `-- composer
        |-- autoload_classmap.php
        |-- autoload_namespaces.php
        |-- autoload_psr4.php
        |-- autoload_real.php
        `-- ClassLoader.php

In test.php kann nun ./vendor/autoload.php eingebunden werden:

PHP:
require __DIR__ . '/vendor/autoload.php';

Fertig.

Wenn sich an der Namespace-/Verzeichnisstruktur etwas ändert, einfach wieder $ composer update ausführen.

Composer unterstützt auch andere Ansätze für Autoloading:

- https://getcomposer.org/doc/04-schema.md#autoload

Der enthaltene Classmap-Generator ist etwa richtig gut, falls du Classmaps, also hinterlegte 1:1-Zuordnungen beliebiger, exakter Pfade zu Klassennamen, nutzen willst.

Composer kann außerdem dazu natürlich noch externe Abhängigkeiten in das Projekt einbinden.

Veränderte composer.json-Datei:

Code:
{
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "mermshaus\\CRC\\": "src"
        }
    },
    "require": {
        "kaloa/filesystem":             "dev-master",
        "kaloa/renderer":               "dev-master",
        "rkr/recursive-array-accessor": "2.0.*"
    }
}

Code:
$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
  - Installing kaloa/filesystem (dev-master d780c0c)
    Cloning d780c0cd7b12c43e7b318a2a08416c24849083a8

  - Installing kaloa/renderer (dev-master d7dcbaa)
    Cloning d7dcbaa40258a8675f44cc9e9ce8e83f0a8b2a4a

  - Installing rkr/recursive-array-accessor (2.0.0)
    Loading from cache

Writing lock file
Generating autoload files

Jetzt kann in test.php etwa das hier stehen:

PHP:
<?php

require __DIR__ . '/vendor/autoload.php';

$markdownRenderer = \Kaloa\Renderer\Factory::createRenderer(null, 'markdown');

echo $markdownRenderer->render('# Hallo Welt

[Ein Link](http://www.example.org/)');

// Ausgabe:

// <h1>Hallo Welt</h1>
//
// <p><a href="http://www.example.org/">Ein Link</a></p>

Man beachte, wie sich Composer um sämtliche Details gekümmert hat.

Dankenswerterweise ist Autoloading/Dependency-Management ein gelöstes Problem.

Auch Pakete, die nicht explizit mit Composer zusammenarbeiten, kannst du mit Composer reinziehen.

Code:
{
    "repositories": [
        {
            "type": "package",
            "package": {
                "name": "geshi/geshi",
                "version": "1.0.8",
                "dist": {
                    "url": "https://github.com/GeSHi/geshi-1.0/archive/c5329d9b39a3e07f2745d1f1dbb3d389657c01e7.zip",
                    "type": "zip"
                },
                "autoload": {
                    "classmap": ["src/"]
                }
            }
        }
    ],
    "require": {
        "geshi/geshi": "1.0.*"
    }
}

Das würde etwa dieses GeSHi holen (per Zip-Archiv-Download) und autoloadbar machen:

- https://github.com/GeSHi/geshi-1.0

Composer generiert dabei automatisch diese Classmap und integriert sie in den Autoloader:

PHP:
<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'GeSHi' => $vendorDir . '/geshi/geshi/src/geshi.php',
);

(Ist jetzt nicht so spektakulär, weil GeSHi nur aus einer Klasse besteht.)

Jedenfalls: Composer ist ein sehr sehr empfehlenswertes Tool.



Edit: Eine Sache noch: Du kannst das, was Composer zusammengesteckt hat, dann einfach auf den Webserver laden. Du hast alle Daten und Sources vorliegen und das ist alles normaler PHP-Code. Es hat keinen Vorteil, die Composer-Software selbst auf dem Zielsystem nutzen zu können. Das ist etwa anders als bei PEAR, wo die Packages in der Regel global auf dem Zielsystem verfügbar sein müssen. Ein „composed“ Projekt ist da vollkommen autark und liefert alles hübsch selbst mit.

Ach ja, das zentrale Repository für Composer-Pakete ist Packagist:

- https://packagist.org/
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück