Question

I am trying to take advantage of autoloading in PHP. I have various classes in different directories, and so I have bootstrapped the autoloading as follows:

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');

It all seems to work fine, but I just wanted to double check that this is indeed considered acceptable practise.

Was it helpful?

Solution

Sure, looks good. The only thing you might do is register them in the order they're most likely to hit. For example, if your most commonly used classes are in services, then vos, then printers, the order you have is perfect. This is because they're queued and called in-order, so you'll achieve slightly better performance by doing this.

OTHER TIPS

You could use:

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

Using spl_autoload_register without arguments will register spl_autoload which will look for the class name in the directories of the include path. Note that this will lowercase the class name before looking for it on the filesystem.

It's okay, but if these are just folders below a certain folder, e.g.

/library
    /JonoB
        /services
        /vos
        /printers

you might want to consider adding these to your classnames, e.g.

JonoB_Services_Foo, JonoB_Vos_Bar, JonoB_Printers_Baz

and then split the $classname by the underscore and take each part as folder name. This is similar to PEAR class name convention. This way you would only have one loader.

Instead of PEAR convention style classnames, you can also use namespaces (autoload example), but be aware that these require PHP5.3 which is not widely available on shared hosting yet. And your application won't be backwards compatible with PHP<5.3 then (if that's an issue).

Good advice from all the other answers.

Let me add that each autoloader should first check if it even cares about the class being passed in, and return immediately if not.

So if you do as Gordon suggests and add a prefix to each class, then for Services_Foo the autoloader autoload_services() should see if "Services_" is the first substring of $class_name, and if not return false immediately to save on any further processing, especially filesystem checks.

If i was supposed to refactor your code, it would be

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');    

I have written my own ClassLoader using spl_autoload_register.
The advantage is that the function looks in every subfolder starting in the current folder.
I simply include this file in every PHP file and never have to worry about any include/require directive.
It simply works :-)

<?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;
}
?>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top