2010-09-14 50 views
30

我想利用PHP中的自动加载。我有不同的目录中的各种班,所以我自举自动加载如下:PHP spl_autoload_register

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

这一切似乎做工精细,但我只是想仔细检查,这确实是认为可以接受的做法。

+1

这里有一个很好的文章[如何使用spl_autoload_register在PHP中自动加载类](http://www.webtipblog.com/using-spl_autoload_register-load-classes-php -项目)。 – joe42 2014-09-05 02:21:41

回答

32

当然,看起来不错。你可能做的唯一事情就是按他们最有可能击中的顺序注册它们。例如,如果您最常用的类是在服务中,那么vos,然后是打印机,您拥有的订单是完美的。这是因为他们排队并按顺序调用,所以通过这样做你可以获得更好的性能。

+17

另外..没有必要使用include/require_once。当系统找不到您正在实例化的类时,自动加载是一种回退。如果您已经通过自动加载包含了一次,那么系统知道它,并且无论如何不会再运行自动加载方法。所以,只需使用常规include/require - 它们更快。 – gidmanma 2011-10-11 03:18:16

4

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

/library 
    /JonoB 
     /services 
     /vos 
     /printers 

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

JonoB_Services_Foo, JonoB_Vos_Bar, JonoB_Printers_Baz 

,然后通过下划线分裂$classname并采取各部分作为文件夹名。这与PEAR class name convention类似。这样你只有一个装载机。

您也可以使用namespacesautoload example)代替PEAR约定风格的类名,但请注意,这些需要PHP5.3,但尚未在共享主机上广泛使用。并且您的应用程序不会向后兼容PHP < 5.3(如果这是个问题)。

+0

这很好,如果你坚持使用PHP <5.3并期望很长一段时间,但正如GameBit所表明的那样,使用命名空间而不是像这样污染你的名字会更好。 (摆脱这种名称污染是Zend Framework 2的主要目标之一。) – 2010-09-14 15:55:39

+0

@ mr.w ZF2将使用名称空间,但据我所知,[ZF2.0将坚持PEAR/PSR-0惯例在文件布局方面,最后还引入了类映射(http://weierophinney.net/matthew/archives/245-Autoloading-Benchmarks.html),所以唯一的区别是解析命名空间而不是类名。 – Gordon 2010-09-14 16:00:07

+0

@ mr.w除此之外,PEAR约定是常见的做法,我很难将其称为命名空间污染。这也是ZF现在所做的。我同意图书馆应该有独特的前缀,以避免与其他图书馆冲突,并补充说。 – Gordon 2010-09-14 16:08:09

3

从所有其他答案的好建议。

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

所以,如果你戈登建议和前缀添加到每个班级,然后Services_Foo自动装卸autoload_services()应该看到,如果“Services_”是$class_name第一子,如果不返回false立即节省任何进一步的处理特别是文件系统检查。

19

你可以使用:

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

使用spl_autoload_register没有参数将注册spl_autoload将寻找在include path的目录中的类名。请注意,这将在文件系统上查找它之前将类名小写。

+8

>小写的类名 --- Gah!为什么?这意味着在Windows上工作的代码可能不在* nix系统上。 – jezmck 2011-09-13 21:50:58

+1

是的,PHP团队认识到这是一个错误,但不会修复向后兼容性。至少在5.3,不知道5.4。 – 2012-05-15 14:43:33

+0

非常漂亮的解决方案!谢谢! – andreas 2012-07-15 01:04:51

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');  
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; 
} 
?> 
相关问题