2009-04-27 11 views
36

Come la maggior parte degli sviluppatori Web in questi giorni, sto godendo appieno dei vantaggi dell'architettura MVC solida per applicazioni e siti Web. Quando si fa MVC con PHP, l'autoloading ovviamente è estremamente utile.Efficienti strategie di caricamento automatico e denominazione PHP

Sono diventato un fan di spl_autoload_register semplicemente definendo una singola funzione __autoload(), in quanto questo è ovviamente più flessibile se si stanno incorporando diversi moduli di base che utilizzano ciascuno il proprio autoloading. Tuttavia, non mi sono mai sentito bene riguardo alle funzioni di caricamento che scrivo. Considono un sacco di controllo delle stringhe e scansione delle directory per cercare le possibili classi da caricare.

Per esempio, diciamo che ho un app che ha un percorso di base definita come PATH_APP, e una struttura semplice con le directory di nome models, views e controllers. Utilizzo spesso una struttura di denominazione in cui i file sono denominati IndexView.php e IndexController.php all'interno della directory appropriata e, in genere, i modelli non hanno uno schema particolare per impostazione predefinita. Potrei avere una funzione loader per questa struttura come questa che viene iscritto su spl_autoload_register:

public function MVCLoader($class) 
{ 
    if (file_exists(PATH_APP.'/models/'.$class.'.php')) { 
     require_once(PATH_APP.'/models/'.$class.'.php'); 
     return true; 
    } 
    else if (strpos($class,'View') !== false) { 
     if (file_exists(PATH_APP.'/views/'.$class.'.php')) { 
      require_once(PATH_APP.'/views/'.$class.'.php'); 
      return true; 
     } 
    } 
    else if (strpos($class,'Controller') !== false) { 
     if (file_exists(PATH_APP.'/controllers/'.$class.'.php')) { 
      require_once(PATH_APP.'/controllers/'.$class.'.php'); 
      return true; 
     } 
    } 
    return false; 
} 

Se non è trovato dopo che, potrei avere un'altra funzione per la scansione di sub-directory nella directory modelli. Tuttavia, tutto il se/else-ing, il controllo delle stringhe e la scansione delle directory mi sembra inefficiente, e mi piacerebbe migliorarlo.

Sono molto curioso di sapere quali strategie di denominazione dei file e di autoloading potrebbero utilizzare altri sviluppatori. Sto cercando in particolare le buone tecniche da impiegare per l'autoloading efficiente e non le alternative all'autoloading.

risposta

28

Questo è quello che ho utilizzato in tutti i miei progetti (sollevato direttamente dalla fonte del l'ultimo):

public static function loadClass($class) 
{ 
    $files = array(
     $class . '.php', 
     str_replace('_', '/', $class) . '.php', 
    ); 
    foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $base_path) 
    { 
     foreach ($files as $file) 
     { 
      $path = "$base_path/$file"; 
      if (file_exists($path) && is_readable($path)) 
      { 
       include_once $path; 
       return; 
      } 
     } 
    } 
} 

Se cerco SomeClass_SeperatedWith_Underscores cercherà SomeClass_SeperatedWith_Underscores.php seguito da SomeClass /SeperatedWith/Underscores.php rooted in ogni directory nel percorso di inclusione corrente.

MODIFICA: Volevo solo metterlo fuori che lo uso per efficienza nello sviluppo e non necessariamente tempo di elaborazione. Se hai la PERA sul tuo percorso, con questo puoi semplicemente usare le classi e non doverle includere quando ne hai bisogno.

Tendo a mantenere le mie classi in una gerarchia di directory, con caratteri di sottolineatura che spezzano gli spazi dei nomi ... Questo codice mi consente di mantenere la struttura del file piacevole e ordinata se lo desidero, o di iniettare un file di classe veloce senza directory annidate se voglio (per l'aggiunta di una singola classe o due per una libreria che è convenuto, ma non fa parte del progetto attualmente sto lavorando su.)

+3

pimp +1 per la freschezza – Louis

+0

Mi piace decisamente l'approccio di sottolineatura. Rende la traduzione da classe a file molto più efficiente. – zombat

+3

Avvolgi 'array_unique()' attorno alla tua matrice '$ files'. Se non c'è un trattino basso nel nome della classe, stai provando ogni file due volte. – mpen

13

sono atterrato su questa soluzione:

ho creato un singolo script che attraversa la mia cartella della libreria di classi (che contiene sottocartelle per moduli/sistemi separati) e analizza il contenuto del file in cerca di definizioni di classe. Se trova una definizione di classe in un file php (abbastanza semplice schema di espressione regolare), si crea un link simbolico:

class_name.php -> actual/source/file.php 

Questo mi permette di utilizzare un unico, semplice funzione autoload che ha bisogno solo il nome della classe e il percorso del cartella symlink principale, e non deve fare alcuna manipolazione di percorso/stringa.

La parte migliore è che posso riorganizzare completamente il mio codice sorgente o aggiungere un nuovo sottosistema e basta eseguire lo script che genera link per avere tutto caricato automaticamente.

+0

Questa è probabilmente la soluzione più creativa che abbia mai incontrato. Roba buona. Solo per curiosità, come sarebbe l'approccio multipiattaforma? – zombat

+4

Da quando ho iniziato a lavorare con linux, uno dei miei principali difetti con Windows è stata la mancanza di collegamenti simbolici. Per quanto ne so, questa soluzione funziona solo con gli unix. – grossvogel

+5

Per tua informazione, puoi usare 'mklink' per creare collegamenti simbolici in Windows: http://www.howtogeek.com/howto/windows-vista/using-symlinks-in-windows-vista/ –

7

Se si desidera l'efficienza, non utilizzare affatto la funzione di caricamento automatico. La funzione di caricamento automatico è per essere pigri. Dovresti fornire un percorso esplicito ai tuoi file di inclusione quando li includi. Se la funzione di caricamento automatico è in grado di trovare questi file, è possibile codificarli per trovarli esplicitamente. Quando si lavora sulla parte di visualizzazione del codice e si sta per caricare una nuova classe di vista, lasciando che la funzione di caricamento automatico la gestisca, si presuppone che la classe sia una classe di modello? Questo è inefficiente. Invece il codice dovrebbe essere solo:

include_once $this->views_path . $class . '.php'; 

Se avete bisogno di più percorsi "vista", fanno una funzione che carica guardati:

public function load_view($class) { 
    // perhaps there's a mapping here instead.... 
    foreach ($this->views_paths as $path) { 
     $filename = $path . $class . '.php'; 
     if (file_exists($filename)) { 
      include_once $filename; 
     } 
    } 
    throw .... 
} 

In ogni caso, nel punto in cui si verifica l'inclusione, è avere le informazioni più accurate/più accurate sulla classe che vuoi caricare. L'utilizzo di tali informazioni per caricare completamente la classe è l'unica strategia di caricamento efficiente della classe. Sì, potresti finire con più variabili di classe o (ci mancherebbe il cielo) alcune variabili globali. Ma questo è un compromesso migliore rispetto al semplice essere pigri e la scansione di parti del file system per la tua classe.

+10

Mentre hai ragione sul caricamento diretto che è il più efficiente in generale, rende il codice più difficile da mantenere. Cosa succede se cambi il nome di una classe o di un file? O dire che ho segmenti di visualizzazione dinamica che possono essere caricati dal controller e, mentre un progetto va avanti, vengono create sempre più classi di visualizzazione. Ogni volta che creo una classe vista, non voglio dover tornare indietro e modificare un controller per includerlo manualmente ovunque possa essere utilizzato. Sono d'accordo sul fatto che il caricamento automatico è meno efficiente del caricamento diretto, ma sto cercando l'autoloading più efficiente. – zombat

+1

Sono d'accordo zombat. La pigrizia può essere una buona cosa - è anche conosciuta come lavorare in modo efficiente. Per quanto riguarda le prestazioni, l'hardware è economico. – rick

+2

Se devi cambiare il nome di una classe dopo che ha colpito la produzione, non stai spendendo abbastanza tempo nella progettazione prima di scrivere il codice. Se l'efficienza è importante, passare più tempo in anticipo risparmia infinitamente più tempo nella manutenzione rispetto a funzioni pigre, non pensate a niente come l'autoload. – jmucchiello

Problemi correlati