PHP spl_autoload_register

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3710480/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 10:48:08  来源:igfitidea点击:

PHP spl_autoload_register

phpspl-autoload-register

提问by JonoB

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:

我正在尝试利用 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');

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

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

回答by mr. w

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.

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

回答by NikiC

You could use:

你可以使用:

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

Using spl_autoload_registerwithout arguments will register spl_autoloadwhich 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.

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

回答by Gordon

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 $classnameby 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.

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

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).

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

回答by Fanis Hatzidakis

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_Foothe 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.

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

回答by Angelin Nadar

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

如果我应该这样做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');    

回答by Michael Hutter

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 :-)

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

<?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;
}
?>