Question

Je me demande quelle est la meilleure pratique pour gérer le problème de devoir "inclure" autant de fichiers dans mes scripts PHP afin de garantir que toutes les classes que j'ai besoin d'utiliser sont accessibles à mon script.

Actuellement, j'utilise simplement include_once pour inclure les cours auxquels j'accède directement.Chacun d'eux serait include_once les cours auxquels ils accèdent.

J'ai envisagé d'utiliser le __autoload fonction, mais hat ne semble pas bien fonctionner si vous envisagez d'organiser vos fichiers de classe dans une arborescence de répertoires.Si vous faisiez cela, il semblerait que vous finiriez par parcourir l'arborescence des répertoires jusqu'à ce que vous trouviez la classe que vous recherchez. De plus, je ne sais pas comment cela affecte les classes portant le même nom dans différents espaces de noms.

Existe-t-il un moyen plus simple de gérer cela ?

Ou PHP n'est-il tout simplement pas adapté à "entreprise" applications de type avec de nombreux objets différents, tous situés dans des fichiers séparés qui peuvent se trouver dans de nombreux répertoires différents.

Était-ce utile?

La solution

J'ai mes candidatures que j'ai habituellement setup.php fichier qui inclut toutes les classes de base (c'est-à-direframework et bibliothèques associées).Mes classes personnalisées sont chargées à l'aide du chargeur automatique aidé par la carte de disposition du répertoire.

Chaque fois qu'une nouvelle classe est ajoutée, j'exécute un script de création de ligne de commande qui analyse toute l'arborescence de répertoires à la recherche de classes de modèle, puis crée un tableau associatif avec des noms de classe comme clés et des chemins comme valeurs.Ensuite, la fonction __autoload recherche le nom de la classe dans ce tableau et obtient le chemin d'inclusion.Voici le code :

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

chargement automatique.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]);
    }
}

Notez que la convention de dénomination des fichiers doit être [class_name].class.php.Modifier les répertoires dans lesquels les classes seront recherchées autobuild.php.Vous pouvez également exécuter l'autobuilder à partir de la fonction de chargement automatique lorsque la classe n'est pas trouvée, mais cela peut mettre votre programme en boucle infinie.

Les tableaux sérialisés sont sacrément rapides.

@JasonMichael :PHP 4 est mort.Passer à autre chose.

Autres conseils

Vous pouvez définir plusieurs fonctions de chargement automatique avec 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;
}

Vous pouvez également déterminer par programme l'emplacement du fichier de classe à l'aide de conventions de dénomination structurées qui correspondent à des répertoires physiques.C'est ainsi que Zend procède Cadre Zend.Alors quand tu appelles Zend_Loader::loadClass("Zend_Db_Table"); il explose le nom de classe dans un tableau de répertoires en le divisant en traits de soulignement, puis la classe Zend_Loader va charger le fichier requis.

Comme tous les modules Zend, je m'attendrais à ce que vous puissiez utiliser uniquement le chargeur seul avec vos propres classes, mais je ne l'ai utilisé que dans le cadre d'un site utilisant le MVC de Zend.

Mais des inquiétudes ont été exprimées concernant les performances sous charge lorsque vous utilisez tout type de chargement de classe dynamique, par exemple voir ce billet de blog comparer Zend_Loader avec le chargement dur des fichiers de classe.

En plus de la pénalité de performances liée à la nécessité de rechercher le chemin d'inclusion PHP, cela annule la mise en cache des opcodes.D'après un commentaire sur ce post :

Lors de l'utilisation de N'IMPORTE QUEL chargeur de classe dynamique, APC ne peut pas mettre entièrement en cache ces fichiers car il ne sait pas quels fichiers seront chargés lors d'une seule requête.En chargeant les fichiers, APC peut les mettre entièrement en cache.

__autoload fonctionne bien si vous avez une convention de dénomination cohérente pour vos classes qui indique à la fonction où elles se trouvent dans l'arborescence des répertoires.MVC se prête particulièrement bien à ce genre de choses car vous pouvez facilement diviser les classes en modèles, vues et contrôleurs.

Vous pouvez également conserver un tableau associatif de noms dans les emplacements de fichiers de votre classe et laisser __autoload interrogez ce tableau.

Parmi les suggestions proposées jusqu'à présent, j'ai un faible pour celle de Kevin, mais il n'est pas nécessaire qu'elles soient absolues.Je vois quelques options différentes à utiliser avec __autoload.

  1. Placez tous les fichiers de classe dans un seul répertoire.Nommez le fichier d'après la classe, c'est-à-dire classes/User.php ou classes/User.class.php.
  2. L'idée de Kevin de placer les modèles dans un répertoire, les contrôleurs dans un autre, etc.Fonctionne bien si toutes vos classes s'intègrent bien dans le framework MVC, mais parfois, les choses deviennent compliquées.
  3. Incluez le répertoire dans le nom de la classe.Par exemple, une classe appelée Model_User serait en réalité située à classes/Model/User.php.Votre fonction __autoload saurait traduire un trait de soulignement en séparateur de répertoire pour trouver le fichier.
  4. Analysez simplement toute la structure des répertoires une fois.Soit dans la fonction __autoload, soit même simplement dans le même fichier PHP où il est défini, parcourez le contenu du classes répertoire et cache quels fichiers se trouvent où.Donc, si vous essayez de charger le User en classe, peu importe si c'est dans classes/User.php ou classes/Models/User.php ou classes/Utility/User.php.Une fois qu'il aura trouvé User.php quelque part dans le classes répertoire, il saura quel fichier inclure lorsque le User la classe doit être chargée automatiquement.

@Kévin :

J'essayais juste de souligner que spl_autoload_register est une meilleure alternative à __autoload puisque vous pouvez définir plusieurs chargeurs et qu'ils n'entreront pas en conflit les uns avec les autres.Pratique si vous devez également inclure des bibliothèques qui définissent une fonction __autoload.

Es-tu sûr?Le Documentation dit différemment :

Si votre code a une fonction __autoload existante, cette fonction doit être explicitement enregistrée sur la pile __autoload.En effet, spl_autoload_register() remplacera effectivement le cache du moteur pour la fonction __autoload par spl_autoload() ou spl_autoload_call().

=> vous devez explicitement enregistrer n'importe quelle bibliothèque __autoload aussi.Mais à part ça, vous avez bien sûr raison, cette fonction est la meilleure alternative.

__autoload fonctionnera, mais uniquement en PHP 5.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top