Frage

Ich frage mich, was die beste Vorgehensweise für den Umgang mit dem Problem ist, dass ich so viele Dateien in meine PHP-Skripte „einbinden“ muss, um sicherzustellen, dass alle Klassen, die ich verwenden muss, für mein Skript zugänglich sind.

Derzeit verwende ich nur include_once um die Kurse einzuschließen, auf die ich direkt zugreife.Jeder von ihnen würde es tun include_once die Klassen, auf die sie zugreifen.

Ich habe versucht, das zu verwenden __autoload Funktion, aber das scheint nicht gut zu funktionieren, wenn Sie planen, Ihre Klassendateien in einem Verzeichnisbaum zu organisieren.Wenn Sie dies getan hätten, würden Sie anscheinend den Verzeichnisbaum durchgehen, bis Sie die gesuchte Klasse gefunden hätten. Außerdem bin ich mir nicht sicher, wie sich dies auf Klassen mit demselben Namen in verschiedenen Namespaces auswirkt.

Gibt es eine einfachere Möglichkeit, damit umzugehen?

Oder ist PHP einfach nicht dafür geeignet?unternehmerischTypanwendungen mit vielen verschiedenen Objekten, die sich alle in separaten Dateien befinden, die sich in vielen verschiedenen Verzeichnissen befinden können.

War es hilfreich?

Lösung

Ich habe normalerweise meine Bewerbungen setup.php Datei, die alle Kernklassen enthält (d. h.Framework und begleitende Bibliotheken).Meine benutzerdefinierten Klassen werden mithilfe eines Autoloaders geladen, der von der Verzeichnislayoutzuordnung unterstützt wird.

Jedes Mal, wenn eine neue Klasse hinzugefügt wird, führe ich ein Befehlszeilen-Builder-Skript aus, das den gesamten Verzeichnisbaum auf der Suche nach Modellklassen durchsucht und dann ein assoziatives Array mit Klassennamen als Schlüsseln und Pfaden als Werten erstellt.Dann sucht die Funktion __autoload nach dem Klassennamen in diesem Array und ruft den Include-Pfad ab.Hier ist der Code:

autobuild.php

define('MAP', 'var/cache/autoload.map');
error_reporting(E_ALL);
require 'setup.php';
print(buildAutoloaderMap() . " classes mapped\n");

function buildAutoloaderMap() {
    $dirs = array('lib', 'view', 'model');
    $cache = array();
    $n = 0;
    foreach ($dirs as $dir) {
        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $entry) {
            $fn = $entry->getFilename();
            if (!preg_match('/\.class\.php$/', $fn))
                continue;
            $c = str_replace('.class.php', '', $fn);
            if (!class_exists($c)) {
                $cache[$c] = ($pn = $entry->getPathname());
                ++$n;
            }
        }
    }
    ksort($cache);
    file_put_contents(MAP, serialize($cache));
    return $n;
}

autoload.php

define('MAP', 'var/cache/autoload.map');

function __autoload($className) {
    static $map;
    $map or ($map = unserialize(file_get_contents(MAP)));
    $fn = array_key_exists($className, $map) ? $map[$className] : null;
    if ($fn and file_exists($fn)) {
        include $fn;
        unset($map[$className]);
    }
}

Beachten Sie, dass die Dateinamenskonvention [Klassenname].class.php lauten muss.Ändern Sie die Verzeichnisse, in denen nach Klassen gesucht wird autobuild.php.Sie können den Autobuilder auch über die Autoload-Funktion ausführen, wenn die Klasse nicht gefunden wird. Dies führt jedoch möglicherweise dazu, dass Ihr Programm in eine Endlosschleife gerät.

Serialisierte Arrays sind verdammt schnell.

@JasonMichael:PHP 4 ist tot.Komm darüber hinweg.

Andere Tipps

Mit spl_autoload_register können Sie mehrere Autoloading-Funktionen definieren:

spl_autoload_register('load_controllers');
spl_autoload_register('load_models');

function load_models($class){
    if( !file_exists("models/$class.php") )
        return false;

    include "models/$class.php";
    return true;
}
function load_controllers($class){
    if( !file_exists("controllers/$class.php") )
        return false;

    include "controllers/$class.php";
    return true;
}

Sie können den Speicherort der Klassendatei auch programmgesteuert bestimmen, indem Sie strukturierte Namenskonventionen verwenden, die physischen Verzeichnissen zugeordnet sind.So macht Zend es Zend Framework.Also, wenn Sie anrufen Zend_Loader::loadClass("Zend_Db_Table"); Es zerlegt den Klassennamen in ein Array von Verzeichnissen, indem es die Unterstriche aufteilt, und dann lädt die Zend_Loader-Klasse die erforderliche Datei.

Wie bei allen Zend-Modulen gehe ich davon aus, dass Sie nur den Loader alleine mit Ihren eigenen Klassen verwenden können, aber ich habe ihn nur als Teil einer Site verwendet, die Zends MVC verwendet.

Es gab jedoch Bedenken hinsichtlich der Leistung unter Last, wenn Sie beispielsweise dynamisches Laden von Klassen verwenden dieser Blogbeitrag Vergleich von Zend_Loader mit dem harten Laden von Klassendateien.

Neben den Leistungseinbußen, die durch das Durchsuchen des PHP-Include-Pfads entstehen, wird auch das Opcode-Caching verhindert.Aus einem Kommentar zu diesem Beitrag:

Bei Verwendung eines beliebigen dynamischen Klassenladers kann APC diese Dateien nicht vollständig zwischenspeichern, da nicht sicher ist, welche Dateien bei einer einzelnen Anfrage geladen werden.Durch hartes Laden der Dateien kann APC sie vollständig zwischenspeichern.

__autoload funktioniert gut, wenn Sie eine konsistente Namenskonvention für Ihre Klassen haben, die der Funktion mitteilt, wo sie im Verzeichnisbaum gefunden werden.MVC eignet sich für solche Dinge besonders gut, da man die Klassen einfach in Modelle, Ansichten und Controller aufteilen kann.

Alternativ können Sie ein assoziatives Array von Namen zu Dateispeicherorten für Ihre Klasse und let beibehalten __autoload Fragen Sie dieses Array ab.

Von den bisherigen Vorschlägen schließe ich mich Kevins Vorschlägen an, aber das muss nicht absolut sein.Ich sehe ein paar verschiedene Optionen für die Verwendung mit __autoload.

  1. Legen Sie alle Klassendateien in einem einzigen Verzeichnis ab.Benennen Sie die Datei nach der Klasse, d. h. classes/User.php oder classes/User.class.php.
  2. Kevins Idee, Modelle in ein Verzeichnis, Controller in ein anderes usw. zu legen.Funktioniert gut, wenn alle Ihre Klassen gut in das MVC-Framework passen, aber manchmal wird es chaotisch.
  3. Fügen Sie das Verzeichnis in den Klassennamen ein.Beispielsweise würde sich eine Klasse namens Model_User tatsächlich unter befinden classes/Model/User.php.Ihre __autoload-Funktion müsste einen Unterstrich in ein Verzeichnistrennzeichen übersetzen, um die Datei zu finden.
  4. Analysieren Sie einfach einmal die gesamte Verzeichnisstruktur.Führen Sie entweder in der __autoload-Funktion oder einfach in derselben PHP-Datei, in der sie definiert ist, eine Schleife über den Inhalt der aus classes Verzeichnis und Cache, welche Dateien sich wo befinden.Wenn Sie also versuchen, das zu laden User Klasse, es spielt keine Rolle, ob es drin ist classes/User.php oder classes/Models/User.php oder classes/Utility/User.php.Sobald es gefunden wird User.php irgendwo in der classes Verzeichnis, weiß es, welche Datei eingefügt werden soll, wenn das User Die Klasse muss automatisch geladen werden.

@Kevin:

Ich wollte nur darauf hinweisen, dass spl_autoload_register eine bessere Alternative zu __autoload ist, da Sie mehrere Loader definieren können und diese nicht miteinander in Konflikt geraten.Praktisch, wenn Sie auch Bibliotheken einbinden müssen, die eine __autoload-Funktion definieren.

Bist du sicher?Der Dokumentation sagt anders:

Wenn Ihr Code über eine vorhandene __autoload-Funktion verfügt, muss diese Funktion explizit im __autoload-Stack registriert werden.Dies liegt daran, dass spl_autoload_register() den Engine-Cache für die Funktion __autoload effektiv entweder durch spl_autoload() oder spl_autoload_call() ersetzt.

=> Sie müssen alle Bibliotheken explizit registrieren __autoload sowie.Aber ansonsten hast du natürlich recht, diese Funktion ist die bessere Alternative.

__autoload wird funktionieren, aber nur in PHP 5.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top