web-dev-qa-db-fra.com

PHP spl_autoload_register

J'essaie de tirer parti du chargement automatique en PHP. J'ai différentes classes dans différents répertoires et j'ai donc amorcé le chargement automatique de la manière suivante:

function autoload_services($class_name)
{
    $file = 'services/' . $class_name. '.php';
    if (file_exists($file))
    {
        require_once($file);
    }
}

function autoload_vos($class_name)
{
    $file = 'vos/' . $class_name. '.php';
    if (file_exists($file))
    {
        require_once($file);
    }
}

function autoload_printers($class_name)
{
    $file = 'printers' . $class_name. '.php';
    if (file_exists($file))
    {
        require_once($file);
    }
}

spl_autoload_register('autoload_services');
spl_autoload_register('autoload_vos');
spl_autoload_register('autoload_printers');

Tout semble bien fonctionner, mais je voulais juste vérifier que cela est bien considéré comme une pratique acceptable.

30
JonoB

Bien sûr, l'air bien. La seule chose que vous puissiez faire est de les enregistrer dans l'ordre dans lequel ils risquent de tomber. Par exemple, si vos classes les plus utilisées sont dans les services, puis vos, puis vos imprimantes, votre commande est parfaite. En effet, ils sont mis en file d'attente et appelés dans l'ordre. Vous obtiendrez ainsi de meilleures performances.

32
mr. w

Vous pouvez utiliser:

set_include_path(implode(PATH_SEPARATOR, array(get_include_path(), './services', './vos', './printers')));
spl_autoload_register();

L'utilisation de spl_autoload_register sans arguments enregistrera spl_autoload qui recherchera le nom de la classe dans les répertoires du include path . Notez que ceci mettra le nom de la classe en minuscule avant de le chercher sur le système de fichiers.

19
NikiC

Ce n'est pas grave, mais s'il ne s'agit que de dossiers situés sous un certain dossier, par exemple.

/library
    /JonoB
        /services
        /vos
        /printers

vous voudrez peut-être envisager de les ajouter à vos noms de classe, par exemple.

JonoB_Services_Foo, JonoB_Vos_Bar, JonoB_Printers_Baz

puis divisez le $classname par le trait de soulignement et prenez chaque partie comme nom de dossier. Ceci est similaire à PEAR convention de nom de classe . De cette façon, vous n’auriez qu’un seul chargeur.

Au lieu de PEAR noms de classe de style convention, vous pouvez également utiliser namespaces ( autoload example ), mais sachez qu'ils nécessitent PHP 5.3 qui n'est pas encore largement disponible sur un hébergement partagé. Et votre application ne sera pas compatible avec PHP <5.3 alors (si c'est un problème).

4
Gordon

Bon conseil de toutes les autres réponses. 

Permettez-moi d'ajouter que chaque autochargeur doit d'abord vérifier s'il se soucie même de la classe transmise et le retourner immédiatement si ce n'est pas le cas.

Donc, si vous faites comme Gordon suggère et ajoutez un préfixe à chaque classe, puis pour Services_Foo l'autoloader autoload_services() devrait voir si "Services_" est la première sous-chaîne de $class_name, et si non renvoyer faux immédiatement pour enregistrer tout traitement ultérieur, en particulier les vérifications du système de fichiers .

3
Fanis

Si je devais _ {refactor your code _, ce serait

function custom_autoload($class_name){
        $dirs = array('services','vos','printers') 
        foreach($dirs as $dir){ 
            $file = $dir.'/'.$class_name. '.php';
            if (file_exists($file)){
               require $file;
               break; // if i have maintained naming conventions as per dir as there
                  // is no point for looking eg: sample1_printer.php in the vos/ 
                 // or printer/. this way iam avoiding unnecessary loop
             }
        }
 }
    spl_autoload_register('custom_autoload');    
2
Angelin Nadar

J'ai écrit mon propre ClassLoader à l'aide de spl_autoload_register.
L'avantage est que la fonction recherche dans chaque sous-dossier commençant dans le dossier actuel.
J'inclus simplement ce fichier dans chaque fichier PHP et je n'ai jamais à me soucier de la directive include/require.
Cela fonctionne simplement :-)

<?php
spl_autoload_register('AutoLoadClasses');

/************************************************************************************
 * AutoLoadClasses
 *
 * Diese Funktion lädt Klassen in gleichnamigen Dateien bei Bedarf automatisch nach,
 * sobald eine (bis dahin unbekannte) Klasse erstmalig instanziert wird.
 * $var = new MeineKlasse; => Es wird nach der Datei class_MeineKlasse.php gesucht
 * Die Suche erfolgt rekursiv in allen Unterordnern ausgehend von dem Ordner, in dem
 * das aufrufende PHP-Script liegt.
 *
 * Michael Hutter / Dezember 2017
 */
function AutoLoadClasses($Klassenname, $StartOrdner = null)
{
    if (is_null($StartOrdner))
    {
        $StartOrdner = __DIR__; # Ausgangspunkt für die Suche: Ordner, in dem sich das aufrufende PHP-Script befindet
        $StartInstanz = true;
    }
    $ZielDateiname = "class_$Klassenname.php";
    $FileList = scandir($StartOrdner, 1); # Sortierung 1 => kommt schneller zum Ziel, falls Ordnernamen im allgemeinen mit einem Großbuchstaben beginnen
    foreach ($FileList as $file) # Alle Dateien und Ordner durchgehen
    {
        $Vollpfad = $StartOrdner.DIRECTORY_SEPARATOR.$file;
        if (is_dir($Vollpfad) && (substr($file, 0, 1) !== '.')) # Ordner?
        {
            #echo "Ordner $StartOrdner<br>";
            $result = AutoLoadClasses($Klassenname, $Vollpfad);
            if ($result) return; # Abbruch, falls Ziel gefunden
        }
        else if (preg_match('/\.php$/i' , $file)) # .php-Datei?
        {
            #echo "$file<br>";
            if ($file == $ZielDateiname) # Dateiname entspricht Klassenname?
            {
                include $Vollpfad;
                return true; # Abbruch aller Rekursionen, da Ziel gefunden
            }
        }
    }
    if (isset($StartInstanz))
        die("<table border bgcolor=red><tr><td>Fehler: Die Datei <b>$ZielDateiname</b> konnte in keinem der Unterordner gefunden werden!</td></tr></table>");
    return false;
}
?>
0
Michael Hutter