30

我正在尝试利用 PHP 中的自动加载。我在不同的目录中有各种类,所以我引导自动加载如下:

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

这一切似乎都很好,但我只是想仔细检查一下这确实被认为是可以接受的做法。

4

6 回答 6

32

当然,看起来不错。您唯一可以做的就是按照它们最有可能命中的顺序注册它们。例如,如果您最常用的类是服务,然后是 vos,然后是打印机,那么您拥有的顺序是完美的。这是因为它们是按顺序排队和调用的,因此您将通过这样做获得稍好的性能。

于 2010-09-14T15:53:50.157 回答
19

你可以使用:

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

不带参数使用spl_autoload_register将注册spl_autoload,它将在include path. 请注意,这将在文件系统上查找类名之前将其小写。

于 2010-09-14T16:04:04.573 回答
4

没关系,但如果这些只是某个文件夹下的文件夹,例如

/library
    /JonoB
        /services
        /vos
        /printers

您可能需要考虑将这些添加到您的类名中,例如

JonoB_Services_Foo, JonoB_Vos_Bar, JonoB_Printers_Baz

然后$classname用下划线分割并将每个部分作为文件夹名称。这类似于PEAR 类名称约定。这样你就只有一个装载机。

除了 PEAR 约定样式的类名,您还可以使用命名空间自动加载示例),但请注意,这些需要 PHP5.3,而共享主机上尚未广泛使用。并且您的应用程序将不会向后兼容 PHP<5.3(如果这是一个问题)。

于 2010-09-14T15:48:37.880 回答
3

所有其他答案的好建议。

让我补充一点,每个自动加载器都应该首先检查它是否关心传入的类,如果不关心则立即返回。

因此,如果您按照 Gordon 的建议为每个类添加前缀,那么对于Services_Foo自动加载器,autoload_services()应该查看“Services_”是否是 的第一个子字符串$class_name,如果不是,则立即返回 false 以节省任何进一步的处理,尤其是文件系统检查。

于 2010-09-14T16:01:46.293 回答
2

如果我应该这样做refactor your code,那就是

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');    
于 2014-04-10T14:22:55.733 回答
0

我已经使用 spl_autoload_register 编写了自己的 ClassLoader。
优点是该函数查找从当前文件夹开始的每个子文件夹。
我只是简单地将这个文件包含在每个 PHP 文件中,而不必担心任何 include/require 指令。
它只是工作:-)

<?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;
}
?>
于 2017-12-23T22:23:53.337 回答