2013-07-23 16 views
5

Ho sperimentato tecniche di mappatura delle directory del caricatore automatico ed è stato un po 'difficile. Sono riuscito a trovare una soluzione abbastanza semplice (in superficie), ma sono totalmente confuso che funzioni, mentre altre soluzioni "più ovvie" hanno fallito. Di seguito sono riportati alcuni frammenti di codice che illustrano la mia confusione.autoloader php: perché funziona?

Ecco il codice di lavoro:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'classes/', 
      'classes/sites/', 
      'classes/data/' 
     ); 
     foreach ($classMap as $location) { 
      if ([email protected]_once($location . $class . '.php')) { // @ SUPPRESSES include_once WARNINGS 
       // CLASS DOESN'T EXIST IN THIS DIRECTORY 
       continue; 
      } else { 
       // CLASS IS AUTO-LOADED 
       break; 
      } 
     } 
    } 
?> 

Ecco un frammento che mi sentivo dovrebbe lavoro, ma non lo fa:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'classes/', 
      'classes/sites/', 
      'classes/data/' 
     ); 
     foreach ($classMap as $location) { 
      if (file_exists($location . $class . '.php')) { 
       require_once ($location . $class . '.php'); 
      } 
     } 
    } 
?> 

Quest'ultimo ha più senso per me perché mentre questi due versioni funzionano:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     require_once ('classes/sites/' . $class . '.php'); 
    } 
?> 

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) {     
     $location = 'classes/sites/';     
     require_once ($location . $class . '.php'); 
    } 
?> 

Questo getta "Nessun file o directory ..." (notare la mancanza di "siti /" nel percorso.

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     require_once ('classes/' . $class . '.php'); 
    } 
?> 

Il "No such file or directory ..." errore mi ha fatto pensare che potrei semplicemente verificare la presenza di file di supporto di una classe e, se (file_exists()) {require_once(); break;} else {continue;}

Perché non funziona? E perché il primo frammento funziona? Il percorso/file di supporto non viene mai esplicitamente incluso o richiesto.

+0

è la directory padre del percorso delle classi in include_paths? – Orangepill

+0

Il file di supporto è incluso, è solo combinato nella dichiarazione if: if (! @include_once ($ location. $ Class. '.php')) –

+0

Sì, stavo pensando che, john500, ma speravo nella conferma , quindi grazie per quello. Mi sembra un modo molto sciatto per ottenere ciò di cui ho bisogno, quindi questo mi limita a raddoppiare il prurito per migliorare la soluzione. Orangepill, non sono sicuro di come farlo ... Non ho lavorato con PHP per un po ', e quando l'ho fatto l'ultima volta, non ero tanto bravo a programmare quanto sono ora ... quindi sto praticamente hackerando PHP cercando di fare cose che so già fare in Java e ColdFusion;). –

risposta

1

OK, l'ho capito. Il mio problema in effetti non era quello di impostare correttamente il percorso; usando la costante __DIR__ c'era il :: ahem :: percorso verso il successo. Ecco il codice di lavoro Ora sto utilizzando:

<?php 
    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'classes/', 
      'classes/sites/', 
      'classes/data/' 
     ); 
     foreach ($classMap as $location) { 
      if (file_exists(__DIR__ . '/' . $location . $class . '.php')) { 
       require_once(__DIR__ . '/' . $location . $class . '.php'); 
       break; 
      } 
     } 
    } 
?> 

Si scopre __DIR__ restituisce il percorso della directory del file vero e proprio in cui è chiamato (a differenza, ad esempio, un file che è includendolo), che significa che funzionerà finché questo file rimane nella directory principale della directory/my. E, esiste esclusivamente per la definizione di questi tipi di impostazioni ...

Spero che questo aiuti qualcun altro in futuro! E, naturalmente, se qualcuno può far luce sul motivo per cui questa soluzione non è ottimale, sono tutti gli occhi ...

EDIT: Un'ottimizzazione che eseguirò sarà la conversione dell'array $ classMap() ad un array associativo (per esempio ,. $classMap = array('root' => 'classes/', 'sites' => 'classes/sites/'); così posso fare una ricerca piuttosto che un ciclo tra tutte le directory che creo nel tempo, ma, suppongo che sia per un altro thread

EDIT2:.. Se qualcuno è interessato, ecco il soluzione che mi è venuta in mente per fare questo come array associativo.In sostanza, ho impostato un array associativo in $ GLOBALS e lo uso per memorizzare una mappa di Classi -> Pacchetti. Quindi, nel caricatore automatico, mappo i pacchetti -> Posizioni e poi chiamare il file necessario per la classe istanziata.

Questo è il file di configurazione globale:

<?php 
    // INITIALIZE GLOBAL Class -> Package map 
    if (!array_key_exists('packageMap',$GLOBALS)) { 
     $GLOBALS['packageMap'] = array(); 
    } 

    spl_autoload_register('my_autoloader'); 

    function my_autoloader($class) { 
     $classMap = array(
      'root'=>'/classes/', 
      'sites'=>'/classes/sites/', 
      'data'=>'/classes/data/' 
     ); 

     // RESOLVE MAPPINGS TO AN ACTUAL LOCATION 
     $classPackage = $GLOBALS['packageMap'][$class]; 
     $location = $classMap[$classPackage]; 
     if (file_exists(__DIR__ . $location . $class . '.php')) { 
      require_once(__DIR__ . $location . $class . '.php'); 
     } 
    } 
?> 

Ecco un file di configurazione sito specifico che utilizza il caricatore automatico:

<?php 
    // LOAD GLOBAL CONFIG FILE  
    require_once('../config/init.php'); 

    // CREATE LOCAL REFERENCE TO GLOBAL PACKAGE MAP (MOSTLY FOR READABILITY) 
    $packageMap = $GLOBALS['packageMap']; 

    // ADD Class -> Package MAPPINGS 
    $packageMap['DAO'] = 'data'; 
    $packageMap['SomeSite'] = 'sites'; 
    $packageMap['PDOQuery'] = 'data'; 

    // INSTANTIATE SOMETHING IN ONE OF THE PACKAGES 
    $someSite = new SomeSite(); 
?> 

Speriamo che questo sia utile per gli altri ...se solleva bandiere rosse per chiunque, per favore inseriscimi. In definitiva, mi piacerebbe sostituire l'uso di $ GLOBALS con apc, ma non è installato sul mio server host: /. Potrei considerare memcached, ma ho sentito recensioni contrastanti ...

+0

Puoi anche usare ['__DIR__'] (http://php.net/manual/en/language.constants.predefined.php) dal PHP 5.3 – Raekye

+0

Ah sì, ancora meglio ... grazie. Codice della soluzione aggiornato –