2009-04-27 5 views
36

Comme la plupart des développeurs web ces jours-ci, je profite à fond les avantages de l'architecture MVC solide pour les applications Web et des sites. En faisant MVC avec PHP, le chargement automatique est évidemment extrêmement pratique. Je suis devenu un fan de spl_autoload_register en définissant simplement une seule fonction __autoload(), car cela est évidemment plus flexible si vous incorporez différents modules de base qui utilisent chacun leur propre chargement automatique. Cependant, je n'ai jamais senti grand au sujet des fonctions de chargement que j'écris. Ils impliquent beaucoup de vérification de chaîne et d'analyse de répertoire afin de rechercher les classes à charger.stratégies auto-chargement et nommage PHP efficace

Par exemple, disons que j'ai une application qui a un chemin de base défini comme PATH_APP, et une structure simple avec des répertoires nommés models, views et controllers. J'emploie souvent une structure de nommage dans lequel les fichiers sont nommés IndexView.php et IndexController.php dans le répertoire approprié, et les modèles ont généralement pas de régime particulier par défaut. Je pourrais avoir une fonction de chargeur pour cette structure comme celle qui obtient inscrit 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; 
} 

Si elle ne trouve après cela, je pourrais avoir une autre fonction pour scanner les sous-répertoires dans le répertoire des modèles. Cependant, tous les tests if/else-ing, string check et directory me semblent inefficaces, et j'aimerais les améliorer.

Je suis très curieux de ce que les noms des fichiers et des stratégies de autoloading autres développeurs pourraient utiliser. Je recherche spécifiquement de bonnes techniques à utiliser pour un chargement automatique efficace, et non des alternatives à l'auto-chargement.

Répondre

28

C'est ce que je l'ai utilisé dans tous mes projets (obtenus directement depuis la source du dernier):

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

Si je cherche SomeClass_SeperatedWith_Underscores il va rechercher SomeClass_SeperatedWith_Underscores.php suivie SomeClass /SeperatedWith/Underscores.php ancré dans chaque répertoire du chemin d'inclusion actuel.

EDIT: Je voulais juste mettre là-bas que je l'utilise pour l'efficacité dans le développement, et pas nécessairement le temps de traitement. Si vous avez PEAR sur votre chemin alors avec cela, vous pouvez simplement utiliser les classes et ne pas avoir à les inclure lorsque vous en avez besoin. J'ai tendance à garder mes classes dans une hiérarchie de répertoires, avec des underscores brisant les espaces de noms ... Ce code me permet de garder la structure de fichier sympa et ordonnée si je veux, ou d'injecter un fichier de classe rapide sans répertoires imbriqués Je veux (pour ajouter une seule classe ou deux à une bibliothèque qu'il est défendeur, mais ne fait pas partie du projet, je travaille actuellement sur.)

+3

pimp +1 pour la fraîcheur – Louis

+0

J'aime beaucoup l'approche de soulignement. Cela rend la traduction de classe en fichier beaucoup plus efficace. – zombat

+3

Enveloppez 'array_unique()' autour de votre tableau '$ files'. S'il n'y a pas de caractère de soulignement dans le nom de classe, vous essayez chaque fichier deux fois. – mpen

13

je suis tombé sur cette solution:

J'ai créé un script qui traverse mon dossier de bibliothèque de classes (qui contient des sous-dossiers pour des modules/systèmes séparés), et analyse le contenu du fichier à la recherche de définitions de classe. Si elle trouve une définition de classe dans un fichier php (modèle regex assez simple), il crée un lien symbolique:

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

Cela me permet d'utiliser une seule, la fonction de chargement automatique simple qui n'a besoin que le nom de classe et le chemin vers la dossier principal de lien symbolique, et n'a aucune manipulation de chemin/chaîne.La meilleure partie est que je peux réorganiser complètement mon code source ou ajouter un nouveau sous-système et exécuter simplement le script générant le lien pour que tout soit chargé automatiquement.

+0

C'est probablement la solution la plus créative que j'ai jamais rencontrée. Bon produit. Juste par curiosité, à quel point cette approche serait-elle multi-plateforme? – zombat

+4

Depuis que j'ai commencé à travailler avec Linux, l'un de mes principaux problèmes avec Windows a été l'absence de liens symboliques. Pour autant que je sache, cette solution ne fonctionne qu'avec les unix. – grossvogel

+5

FYI, vous pouvez utiliser 'mklink' pour créer des liens symboliques dans Windows: http://www.howtogeek.com/howto/windows-vista/using-symlinks-in-windows-vista/ –

7

Si vous voulez de l'efficacité, vous ne devriez pas du tout utiliser la fonction de chargement automatique. La fonction de chargement automatique est d'être paresseux. Vous devez fournir un chemin explicite à vos fichiers d'inclusion lorsque vous les incluez. Si votre fonction de chargement automatique peut trouver ces fichiers, vous pouvez les coder pour les trouver explicitement. Lorsque vous travaillez sur la partie vue du code et sur le point de charger une nouvelle classe d'affichage, en laissant la fonction autoload la gérer, elle suppose d'abord que votre classe est une classe modèle. C'est inefficace. Au lieu de cela votre code doit être juste:

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

Si vous avez besoin de plusieurs chemins « vue », une fonction qui charge vues:

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

Dans tous les cas, au moment où l'inclusion apparaît, vous avoir l'information la plus grande/la plus précise sur la classe que vous voulez charger. Utiliser cette information pour charger complètement la classe est la seule stratégie efficace de chargement de classe. Oui, vous pouvez vous retrouver avec plus de variables de classe ou (au paradis) certaines variables globales. Mais c'est un meilleur compromis que d'être simplement paresseux et de numériser des parties du système de fichiers pour votre classe.

+10

Bien que vous ayez raison sur le fait que le chargement direct soit le plus efficace dans l'ensemble, cela rend le code plus difficile à maintenir. Que faire si vous changez le nom d'une classe ou d'un fichier? Ou disons que j'ai des segments de vue dynamiques qui peuvent être chargés par le contrôleur, et qu'un projet se poursuit, de plus en plus de classes d'affichage sont créées. Chaque fois que je crée une classe de vue, je ne veux pas devoir revenir en arrière et modifier un contrôleur pour l'inclure manuellement là où il pourrait être utilisé. Je suis d'accord pour dire que le chargement automatique est moins efficace que le chargement direct, mais je cherche l'autoloading le plus efficace. – zombat

+1

Je suis d'accord zombat. La paresse peut être une bonne chose - c'est aussi connu comme un travail efficace. En ce qui concerne les performances, le matériel est bon marché. – rick

+2

Si vous devez changer le nom d'une classe après la production, vous ne passez pas assez de temps à concevoir avant d'écrire du code. Si l'efficacité est importante, passer plus de temps à l'avance économise infiniment plus de temps en maintenance que les fonctions paresseuses, ne pas penser à tout, comme le chargement automatique. – jmucchiello

Questions connexes