Domanda

Mi chiedo quale sia la migliore pratica per gestire il problema di dover "includere" così tanti file nei miei script PHP per garantire che tutte le classi che devo utilizzare siano accessibili al mio script.

Attualmente sto solo usando include_once per includere le classi a cui accedo direttamente.Ognuno di questi lo farebbe include_once le classi a cui accedono.

Ho esaminato l'utilizzo di __autoload funzione, ma hat non sembra funzionare bene se prevedi di organizzare i file della classe in un albero di directory.Se lo facessi, sembra che finiresti per percorrere l'albero delle directory finché non troverai la classe che stavi cercando. Inoltre, non sono sicuro di come questo influisca sulle classi con lo stesso nome in spazi dei nomi diversi.

C'è un modo più semplice per gestire questa cosa?

Oppure PHP semplicemente non è adatto a "intraprendente" applicazioni di tipo con molti oggetti diversi, tutti posizionati in file separati che possono trovarsi in molte directory diverse.

È stato utile?

Soluzione

Di solito ho le mie applicazioni setup.php file che include tutte le classi principali (ad es.framework e librerie di accompagnamento).Le mie classi personalizzate vengono caricate utilizzando il caricatore automatico aiutato dalla mappa del layout della directory.

Ogni volta che viene aggiunta una nuova classe, eseguo lo script di creazione della riga di comando che esegue la scansione dell'intero albero di directory alla ricerca di classi di modelli, quindi crea array associativi con nomi di classi come chiavi e percorsi come valori.Quindi, la funzione __autoload cerca il nome della classe nell'array e ottiene il percorso di inclusione.Ecco il codice:

autobuild.php

define('MAP', 'var/cache/autoload.map');
error_reporting(E_ALL);
require 'setup.php';
print(buildAutoloaderMap() . " classes mapped\n");

function buildAutoloaderMap() {
    $dirs = array('lib', 'view', 'model');
    $cache = array();
    $n = 0;
    foreach ($dirs as $dir) {
        foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir)) as $entry) {
            $fn = $entry->getFilename();
            if (!preg_match('/\.class\.php$/', $fn))
                continue;
            $c = str_replace('.class.php', '', $fn);
            if (!class_exists($c)) {
                $cache[$c] = ($pn = $entry->getPathname());
                ++$n;
            }
        }
    }
    ksort($cache);
    file_put_contents(MAP, serialize($cache));
    return $n;
}

caricamento automatico.php

define('MAP', 'var/cache/autoload.map');

function __autoload($className) {
    static $map;
    $map or ($map = unserialize(file_get_contents(MAP)));
    $fn = array_key_exists($className, $map) ? $map[$className] : null;
    if ($fn and file_exists($fn)) {
        include $fn;
        unset($map[$className]);
    }
}

Tieni presente che la convenzione di denominazione dei file deve essere [nome_classe].class.php.Modificare le directory in cui verranno esaminate le classi autobuild.php.Puoi anche eseguire l'autobuilder dalla funzione di caricamento automatico quando la classe non viene trovata, ma ciò potrebbe far entrare il tuo programma in un ciclo infinito.

Gli array serializzati sono dannatamente veloci.

@JasonMichael:PHP 4 è morto.Farsene una ragione.

Altri suggerimenti

Puoi definire più funzioni di caricamento automatico con spl_autoload_register:

spl_autoload_register('load_controllers');
spl_autoload_register('load_models');

function load_models($class){
    if( !file_exists("models/$class.php") )
        return false;

    include "models/$class.php";
    return true;
}
function load_controllers($class){
    if( !file_exists("controllers/$class.php") )
        return false;

    include "controllers/$class.php";
    return true;
}

È inoltre possibile determinare a livello di codice la posizione del file di classe utilizzando convenzioni di denominazione strutturate che eseguono il mapping alle directory fisiche.Ecco come lo fa Zend Quadro Zend.Quindi quando chiami Zend_Loader::loadClass("Zend_Db_Table"); esplode il nome della classe in un array di directory suddividendolo in caratteri di sottolineatura, quindi la classe Zend_Loader va a caricare il file richiesto.

Come tutti i moduli Zend, mi aspetterei che tu possa utilizzare solo il caricatore da solo con le tue classi, ma l'ho usato solo come parte di un sito che utilizza MVC di Zend.

Ma ci sono state preoccupazioni sulle prestazioni sotto carico quando si utilizza qualsiasi tipo di caricamento di classi dinamiche, ad esempio vedere questo post del blog confrontando Zend_Loader con il caricamento intenso dei file di classe.

Oltre alla penalizzazione in termini di prestazioni derivante dalla necessità di cercare nel percorso di inclusione PHP, ciò vanifica la memorizzazione nella cache del codice operativo.Da un commento su quel post:

Quando si utilizza QUALSIASI caricatore di classi dinamiche, APC non è in grado di memorizzare completamente nella cache tali file poiché non è sicuro di quali file verranno caricati su ogni singola richiesta.Caricando i file, APC può memorizzarli completamente nella cache.

__autoload funziona bene se hai una convenzione di denominazione coerente per le tue classi che indica alla funzione dove si trovano all'interno dell'albero delle directory.MVC si presta particolarmente bene per questo genere di cose perché puoi facilmente dividere le classi in modelli, visualizzazioni e controller.

In alternativa, mantieni un array associativo di nomi per archiviare le posizioni della tua classe e lascialo __autoload interroga questo array.

Tra i suggerimenti finora, sono parziale con quello di Kevin, ma non è necessario che siano assoluti.Vedo un paio di opzioni diverse da utilizzare con __autoload.

  1. Metti tutti i file di classe in un'unica directory.Assegna un nome al file dopo la classe, ad esempio classes/User.php O classes/User.class.php.
  2. L'idea di Kevin di mettere i modelli in una directory, i controller in un'altra, ecc.Funziona bene se tutte le tue classi si adattano perfettamente al framework MVC, ma a volte le cose si complicano.
  3. Includere la directory nel nome della classe.Ad esempio, una classe chiamata Model_User si troverebbe effettivamente in classes/Model/User.php.La tua funzione __autoload saprebbe tradurre un carattere di sottolineatura in un separatore di directory per trovare il file.
  4. Basta analizzare l'intera struttura della directory una volta.Nella funzione __autoload, o anche solo nello stesso file PHP in cui è definito, esegui il loop sul contenuto di classes directory e memorizzare nella cache quali file sono dove.Quindi, se provi a caricare il file User classe, non importa se è in classe classes/User.php O classes/Models/User.php O classes/Utility/User.php.Una volta trovato User.php da qualche parte nel classes directory, saprà quale file includere quando il file User la classe deve essere caricata automaticamente.

@Kevin:

Stavo solo cercando di sottolineare che spl_autoload_register è un'alternativa migliore a __autoload poiché puoi definire più caricatori e non entreranno in conflitto tra loro.Utile se devi includere anche librerie che definiscono una funzione __autoload.

Sei sicuro?IL documentazione dice diversamente:

Se il tuo codice ha una funzione __autoload esistente, questa funzione deve essere registrata esplicitamente nello stack __autoload.Questo perché spl_autoload_register() sostituirà effettivamente la cache del motore per la funzione __autoload con spl_autoload() o spl_autoload_call().

=> devi registrare esplicitamente qualsiasi libreria __autoload anche.Ma a parte questo ovviamente hai ragione, questa funzione è l'alternativa migliore.

__autoload funzionerà, ma solo in PHP 5.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top