2010-09-14 11 views
30

Próbuję skorzystać z automatycznego ładowania w PHP. Mam różne zajęcia w różnych katalogach, a więc mam bootstrapped automatyczne ładowanie się następująco: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'); 

To wszystko wydaje się działać prawidłowo, ale po prostu chciałem, aby dokładnie sprawdzić, że to rzeczywiście jest uważana za akceptowalną praktyką.

+1

Oto dobry artykuł na temat [jak używać spl_autoload_register do klas autoLoad w php] (http://www.webtipblog.com/using-spl_autoload_register-load-classes-php -projekt). – joe42

Odpowiedz

32

Oczywiście, wygląda dobrze. Jedyne, co możesz zrobić, to zarejestrować je w kolejności, w jakiej najprawdopodobniej trafią. Na przykład, jeśli najczęściej używane klasy znajdują się w usługach, to vos, a następnie drukarki, kolejność, którą masz, jest idealna. Dzieje się tak dlatego, że są one kolejkowane i wywoływane w kolejności, dzięki czemu osiągniesz nieco lepszą wydajność.

+17

Również .. nie trzeba używać include/require_once. Automatyczne ładowanie jest awarią, gdy system nie może znaleźć tworzonej klasy. Jeśli już raz podałeś go za pośrednictwem autoloady, system o tym wie i nie będzie już tak czy inaczej uruchamiał metody autoloadowania. Tak więc, po prostu użyj zwykłego uwzględnienia/wymagania - są one szybsze. – gidmanma

4

Jest w porządku, ale jeśli są to tylko foldery poniżej określonego folderu, np.

/library 
    /JonoB 
     /services 
     /vos 
     /printers 

możesz rozważyć dodanie ich do swoich nazw klas, np.

JonoB_Services_Foo, JonoB_Vos_Bar, JonoB_Printers_Baz 

a następnie podzielić $classname przez podkreślenia i podjąć każdą część jak nazwa folderu. Jest to podobne do PEAR class name convention. W ten sposób masz tylko jeden program ładujący.

Zamiast nazw klas stylu konwencji PEAR można również użyć namespaces (autoload example), ale należy pamiętać, że wymagają one PHP5.3, które nie jest jeszcze powszechnie dostępne w hostingu współdzielonym. Twoja aplikacja nie będzie kompatybilna wstecz z PHP < 5.3 (jeśli jest to problem).

+0

Jest to dobre, jeśli utkniesz w PHP <5.3 i spodziewasz się, że będzie przez długi czas, ale jak wskazuje GameBit, znacznie lepiej wykorzystujesz przestrzenie nazw zamiast zanieczyszczać takie nazwy. (Odejście od takiego nazewnictwa jest jednym z głównych celów Zend Framework 2.) –

+0

@ mr.w ZF2 użyje przestrzeni nazw, ale o ile mi wiadomo, [ZF2.0 będzie trzymać się konwencji PEAR/PSR-0 pod względem układu plików i ewentualnie wprowadzenia mapowania klas) (http://weierophinney.net/matthew/archives/245-Autoloading-Benchmarks.html), więc jedyną różnicą jest parsowanie przestrzeni nazw zamiast nazwy klasy. – Gordon

+0

@ mr.w poza tym, konwencja PEAR jest powszechną praktyką i nie nazwałbym jej zanieczyszczaniem przestrzeni nazw. ZF robi to teraz. Zgodzę się na to, że biblioteka powinna mieć unikalny prefiks, aby uniknąć konfliktów z innymi bibliotekami i dodała to. – Gordon

3

Dobra rada od wszystkich innych odpowiedzi.

Pozwolę sobie dodać, że każdy automatyczny ładujący powinien najpierw sprawdzić, czy nawet dba o to, aby klasa została przekazana i natychmiast powrócić, jeśli nie.

Więc jeśli nie jak sugeruje Gordon i dodać przedrostek do każdej klasy, a następnie do Services_Foo Autoloader autoload_services() należy sprawdzić, czy „Services_” to pierwsza podłańcuchem $class_name, a jeśli nie zwróci false natychmiast zaoszczędzić na jakiekolwiek dalsze przetwarzanie , szczególnie sprawdza system plików.

19

Można użyć:

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

Korzystanie spl_autoload_register bez argumentów zarejestruje spl_autoload który będzie szukał nazwy klasy w katalogach z include path. Zauważ, że będzie to małe litery nazwy klasy przed szukaniem jej w systemie plików.

+8

> małe litery nazwa klasy --- Gah! Czemu? Oznacza to, że kod działający w systemie Windows może nie działać w systemach * nix. – jezmck

+1

Tak, zespół php rozpoznaje to jako błąd, ale nie naprawię kompatybilności wstecznej. Przynajmniej w 5.3, nie wiem o 5.4. –

+0

Bardzo piękne rozwiązanie imo! Dzięki! – andreas

2

Gdybym miał refactor your code byłoby

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

Pisałem własne ClassLoader użyciu spl_autoload_register.
Zaletą jest to, że funkcja wygląda w każdym podfolderze rozpoczynającym się w bieżącym folderze.
Po prostu dołączam ten plik do każdego pliku PHP i nigdy nie muszę się martwić o żadną dyrektywę include/require.
To po prostu działa :-)

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