Tutorial: Teil2 - Der Autoloader

BasicAvid

Member
Hallo zusammen,

im ersten Teil hab ich euch gezeigt wie man einen einfachen FrontController aufbauen kann. Aber bis jetzt, gehen dem FrontController noch ein paar Klassen ab die er zum korrekten arbeiten braucht.

Deshalb erstellen wir uns heute einen Autoloader, der für das includen von allen Klassen verantwortlich ist. Bei einem kleinen Projekt funktioniert das ja noch ganz gut mit include("blablubb.class.php"), doch ab einer bestimmten größe kann man so leicht den überblick der includierten Klassen verlieren. Und hier zeigt dann der Autoloader seine Stärken.

Seit der PHP5 Version gibts eine nette Funktion, die sich __autoload() nennt. Diese Funktion includiert automatisch Files. Das mal als sehr grobe Erklärung. Was Sie genau macht, könnt Ihr euch ja hier durchlesen.

Ok, als ersten öffnen wir die im ersten Teil unter core angelegte AutoLoader.class.php Datei, und erstellen darin die Klasse mit ihren Attributen und Methoden.

PHP:
class AutoLoader {
    
    private static $packages = array(); // Hier werden die zu includierenden Klassen samt Pfad gespeichert
    
    public function __construct() {
    }

    public static function addPackage($package) {
    
    }

    public static function addClass($class) {

    }

    public static function autoLoadPackage($classname) {

    }

    private static function readPath($package) {

    }

    private static function hasWildcard($package) {

    }

    private static function getPackages() {

    }
}

/**
 * Hier wird die __autoload() Funktion von PHP aufgerufen, die wiederum unsere
 * statische AutoLoader Methode aufruft, in der dann die Datei includiert wird.
 * @param Zu includierende Klasse
 */
function __autoload($classname) {
     AutoLoader::autoLoadPackage($classname);
}

Soviel zum Skelett der Klasse.

Als nächstes machen wir uns an die implementierung der einzelnen Methoden.

PHP:
    /**
     * Lädt entweder eine Klasse oder falls ein * Wildcard
     * angegeben wurde das komplette Verzeichniss ein.
     * Das ganze sollte aber mit bedacht eingesetzt werden.
     * 
     * @param string "Pfad/Dateiname" "Pfad/*"
     */
    public static function loadPackage($package) {
        // Prüfen ob es sich um eine Datei handelt
        if (is_file($package) && ! in_array($package, self::$packages)) { 
            self::$packages[] = $package;          
        } else {
            if (self::hasWildcard($package)) { // Auf Wildcards prüfen           
                self::readPath($package); // Falls Wildcards gefunden wurden, wird das Verzweichniss eingelesen.                 
            }
        }         
    }

Man könnte/sollte hier natürlich noch ein Exception-/Error-Handling einbauen, das ganze gilt auch für die nachfolgenden Methoden.

PHP:
    /**
     * Nimmt eine einzelne Datei/Klasse auf.
     *
     * @param string "Pfad/Dateiname"
     */
    public static function addPackage($package) {
        // Das gleiche wie unter loadPackage()    
        if (is_file($package) && ! in_array($package, self::$packages)) {
            self::$packages[] = $package;                                         
        }  
    }

Jetzt machen wir uns an die wichtigste Methode in dieser Klasse, der autoLoadPackage() Methode.

PHP:
	/**
	  * Diese Methode wird von der function __autoload()
	  * aufgerufen. Sie ist es, die die Klassen includiert.
	  * 
	  * @param string Classname
	  */	
    public static function autoLoadPackage($classname) {        
        foreach (self::$packages as $package) {            
            if (strstr($package, $classname)) {                
                require_once($package);
            }
        }
    }


PHP:
    /**
     * Diese Methode liest alle Klasse/Files in einem Verzeichniss ein.
     *
     * @param string Pfad
     */
    private static function readPath($package) {
		// Wildcards entfernen
        $package = preg_replace('/[*|*.*]/','',$package);
		// Verzeichniss öffnen
        $dir = opendir($package);
		// Verzeichniss auslesen und zum Package-Array hinzufügen
        while ($file = readdir($dir)) {            
            if (!is_dir($package.$file)) {                
                self::addPackage($package.$file);                               
            } 
        }
		// Verzeichniss wieder schliessen
        closedir($dir);
    }

So, jetzt sind wir fast am Ende der Klasse angekommen.

PHP:
    /**
     * Prüft das Package auf Wildcards
     *
     * @param string Pfad
     */
    private static function hasWildcard($package) {
        if (preg_match('/[*|*.*]/',$package)) {
            return true;
        }
        return false;
        
    }

Die letzte Methode ist eigentlich nur dafür gedacht, dass man sich mal alle geladenen Files holen kann.

PHP:
    private static function getPackages() {
        return $this->packages;
    }

Gut, und schon sind wir am Ende der Klasse angekommen. Die Klasse als ganze, gibts im Anhang.

Bei fragen einfach hier antworten, danke.

Im nächsten Teil machen wir uns dann an eine kleine Template-Klasse.

Also, bis denne.
 

easteregg

Member of Honour
heyho,

was ich bei dem autoloader von dir nicht so ganz verstehe ist die tatsache, dass ich ja dennoch erstmal die files via addPackage() bzw. addPath() hinzufügen muss, führt das die eigentlich intention dieser __autoload function nicht ad absurdum?
 

BasicAvid

Member
Naja, die __autoloader() Funktion muss ja wissen wo sich die Klasse befindet. Deshalb dieses addPackage() und addClass(), denen ja nur der Pfad und/oder die Klasse übergeben wird.

führt das die eigentlich intention dieser __autoload function nicht ad absurdum?

Nö, da die __autoloader() Funktion dafür da ist, Klassen die includiert werden müssen, wirklich erst dann zu includieren, wenn z.B. eine Instanz der Klasse erzeugt wird.

Wenn sich Deine Klassen alle im gleichen Verzeichnis befinden, kannst Du dass ja der __autoloader() Funktion mit auf den Weg geben.

Ab der PHP 5.3 Version funktioniert das ganze dann viel schöner, denn dann gibts endlich Namespaces für PHP.
 

.wired

New member
Sehr geiles Tutorial, auch wenn ich es nur überflogen habe. Vielleicht habe ich ja noch ein paar Fragen dezu, wenn ich mich näher damit befasse, auf jeden Fall ist es genau, was ich suche.

Eine etwas persönlichere Frage: Was für ein Programmierer bist du denn genau? Eben PHP? PERL? Oder gar nicht mal Websprachen, sondern eher zu C hin?

MfG .wired
 

BasicAvid

Member
Eine etwas persönlichere Frage: Was für ein Programmierer bist du denn genau? Eben PHP? PERL? Oder gar nicht mal Websprachen, sondern eher zu C hin?

Tja, ich bin Programmierer. Die Sprache ist egal, klar, ich habe meine Lieblingssprachen welche PHP und C# wären aber ich programmiere auch in C/C++, Java, VB, Delphi usw.. Es kommt halt immer drauf an was ich machen will. Aber eigentlich bin ich reiner PHP-Programmierer.
 
Oben