Le performance subirebbero l'autoload in php e la ricerca del file di class?

Ho sempre lottato con il modo migliore per includere le classi nel mio codice php. Il pathing è di solito un problema, ma pochi minuti fa ho trovato questa domanda che lo aiuta drammaticamente. Ora sto leggendo su __autoload e penso che potrebbe rendere molto più facile il process di sviluppo delle mie applicazioni. Il problema è che mi piace mantenere la struttura delle cartelle per separare le aree di funzionalità anziché lanciare tutto in una cartella generale / lib. Quindi, se eseguo l'override del caricamento automatico per eseguire una ricerca approfondita di una cartella di class che includa tutte le sottocartelle, quali risultati di performance posso aspettarmi?

Ovviamente ciò dipenderà dalla scala, dalla profondità della struttura delle cartelle e dal numero di classi, ma generalmente chiederò a un progetto su scala media causerà problemi.

__autoload è ottimo, ma il costo di dichiarare tutti i file in una function di ricerca ricorsiva è costoso. Potresti voler build un tree di file da usare per l'autoloading. Nel mio framework, nomino costantemente i file per le loro classi e uso una mappa che viene memorizzata nella cache per i dati.

Controlla http://trac.framewerk.org/cgi-bin/trac.fcgi/browser/trunk/index.php [ dead link ] a partire dalla row 68 per un'idea di come ciò possa essere fatto.

Modifica: per rispondere in modo più diretto alla tua domanda senza cache, puoi aspettarti un riscontro in termini di performance su un sito con traffico medio-pesante.

Un model comune (Pear, Zend Framework come esempi …) serve a far riflettere il path sul nome della class, quindi Db_Adapter_Mysql si troverà in /Db/Adapter/Mysql.php, da qualche parte aggiunta al path include.

Ci sono 2 modi in cui potresti facilmente farlo, innanzitutto nominare le tue classi in modo che definiscano la struttura di where trovarle

function __autoload($classname) { try { if (class_exists($classname, false) OR interface_exists($classname, false)) { return; } $class = split('_', strtolower(strval($classname))); if (arrays_shift($class) != 'majyk') { throw new Exception('Autoloader tried to load a class that does not belong to us ( ' . $classname . ' )'); } switch (count($class)) { case 1: // Core Class - matches Majyk_Foo - include /core/class_foo.php $file = MAJYK_DIR . 'core/class_' . $class[0] . '.php'; break; case 2: // Subclass - matches Majyk_Foo_Bar - includes /foo/class_bar.php $file = MAJYK_DIR . $class[0] . '/class_' . $class[1] . '.php'; break; default: throw new Exception('Unknown Class Name ( ' . $classname .' )'); return false; } if (file_exists($file)) { require_once($file); if (!class_exists($classname, false) AND !interface_exists($classname, false)) { throw new Exception('Class cannot be found ( ' . $classname . ' )'); } } else { throw new Exception('Class File Cannot be found ( ' . str_replace(MAJYK_DIR, '', $file) . ' )'); } } catch (Exception $e) { // spl_autoload($classname); echo $e->getMessage(); } } 

Oppure, 2, usa più caricatori automatici. PHP> = 5.1.2 Ha la libreria SPL, che consente di aggiungere più caricatori automatici. Ne aggiungi uno per each path e lo troverà nel suo path. O semplicemente aggiungili al path di inclusione e usa il default spl_autoload ()

Un esempio

 function autoload_foo($classname) { require_once('foo/' . $classname . '.php'); } function autoload_bar($classname) { require_once('bar/' . $classname . '.php'); } spl_autoload_register('autoload_foo'); spl_autoload_register('autoload_bar'); spl_autoload_register('spl_autoload'); // Default SPL Autoloader 

Autoload è un'ottima funzionalità PHP che ti aiuta moltissimo … La perfomance non ne risentirebbe se usassi la tassonomia intelligente come: 1. each libreria rimane nelle cartelle "pacchetti" 2. each class si trova sostituendo il "_" nel nome della class con "/" e aggiungendo un ".php" alla fine class = My_App_Smart_Object file = packages / My / App / Smart / Object.php

I vantaggi di questo approccio (utilizzato da quasi tutti i framework) è anche una organizzazione più intelligente del tuo codice 🙂

La ricerca di file dappertutto renderà le cose più lente (molti più colpi al disco). Caricando tutte le tue classi nel caso in cui tu ne abbia bisogno, le cose richiederanno più memory. Specificare quali classi sono necessarie in each file è difficile da mantenere (ovvero non vengono rimosse se non vengono più utilizzate).

La vera domanda è quale di questi è più importnte per te? Sono tutti compromessi, alla fine, quindi devi sceglierne uno. È discutibile, tuttavia, che la maggior parte del sovraccarico nella seconda e terza opzione ha a che fare con la compilazione del codice. L'uso di qualcosa come APC può ridurre in modo significativo il sovraccarico di caricamento e compilazione di each class su each carico di pagina.

Dato l'uso di APC, probabilmente prenderei l'approccio di dividere il mio codice in moduli (ad esempio il module di interface web, il module di interazione del database, ecc.) E ciascuno di questi moduli importerà tutte le classi per il loro module, oltre alle classi da altri moduli di cui potrebbero aver bisogno. È un compromesso tra gli ultimi due, e ho trovato che funziona abbastanza bene per le mie esigenze.

Tendo ad usare un approccio semplice in cui __autoload () consulta i nomi di classi di hash mapping in routes relativi, contenuti in un file che viene rigenerato utilizzando un semplice script che esegue la ricerca ricorsiva.

Ciò richiede che lo script venga eseguito quando si aggiunge un nuovo file di class o si ristruttura il code base, ma si evita anche "intelligenza" in __autoload () che può portre a chiamate stat () non necessarie, e ha il vantaggio che posso spostarmi facilmente file nella mia base di codice, sapendo che tutto ciò che devo fare è eseguire un singolo script per aggiornare il caricatore automatico.

Lo script stesso ispeziona ricorsivamente la mia include / directory e presume che qualsiasi file PHP non nominato in un breve elenco di esclusioni (lo stesso autoloader, più alcuni altri file standard che tendo ad avere) contenga una class con lo stesso nome.

L'approccio di Zend Framework è quello di eseguire il caricamento automatico in base allo standard della cartella PEAR (Class_Foo esegue il mapping a /Class/Foo.php), tuttavia, anziché utilizzare un path di base impostato, utilizza include_path.

Il problema con il loro approccio è che non c'è modo di controllare in anticipo se esiste un file così il caricamento automatico cercherà di includere un file che non esiste in nessuno dei routes di include, di uscire e non dare mai altre funzioni di autoload registrate con spl_autoload_register a possibilità di includere il file.

Quindi una leggera deviazione è quella di fornire manualmente una serie di routes di base in cui il caricamento automatico può aspettarsi di trovare l'installazione delle classi in modo PEAR e semplicemente eseguire il loop sui routes di base:

 <?php //... foreach( $paths as $path ) { if( file_exists($path . $classNameToFilePath) ) include $path . $classNameToFilePath; } //... ?> 

Certo, sarai come una ricerca, ma per each caricamento automatico farai solo le peggiori ricerche, where n è il numero di routes di base che stai controllando.

Ma se ti trovi ancora a wherer ricorrere alle directory ricorsive, la domanda non è "Il caricamento automatico danneggerà la mia performance", la domanda dovrebbe essere "perché sto lanciando i miei file di class in una struttura random?" Attenersi alla struttura PEAR ti farà risparmiare così tanti mal di testa, e anche se decidi di andare manualmente facendo il tuo include al contrario di autoload, non ci saranno ipotesi su where si trovano i file di class quando fai le tue istruzioni di inclusione.