40 votes

Efficace PHP automatique de chargement et de stratégies de noms

Comme la plupart des développeurs web ces jours-ci, je suis à fond en profitant des avantages de la solide architecture MVC pour les applications web et des sites. Lorsque vous faites MVC en PHP, le chargement automatique de toute évidence est extrêmement pratique.

Je suis devenu un fan de spl_autoload_register par rapport à la simple définition d'une __autoload() de la fonction, comme c'est évidemment plus souple si vous êtes en intégrant différents modules de base que chaque utilisation de leur propre auto-chargement. Cependant, je n'ai jamais ressenti une grande sur les fonctions de chargement que j'écris. Elles impliquent beaucoup de cordes vérification et le répertoire de la numérisation afin de rechercher des classes à charger.

Par exemple, disons que j'ai une application qui a un chemin d'accès de base défini comme PATH_APP, et d'une structure simple, avec des répertoires nommés models, views et controllers. J'utilise souvent une structure de nommage où les fichiers sont nommés IndexView.php et IndexController.php à l'intérieur du répertoire approprié, et les modèles n'ont généralement pas d'un régime particulier, par défaut. Je pourrais avoir un chargeur de fonction de cette structure comme celle-ci qui s'inscrit avec 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 il ne l'est pas après, j'ai peut être une autre fonction pour scanner les sous-répertoires dans le répertoire des modèles. Cependant, tous les if/else-ing, chaîne de la vérification et de l'examen de répertoire semble inefficace pour moi, et je voudrais l'améliorer.

Je suis très curieux de ce que les noms de fichier et le chargement automatique des stratégies d'autres développeurs peuvent utiliser. Je suis à la recherche spécifiquement pour les bonnes techniques à employer pour l'efficacité de chargement automatique, et non pas d'options pour le chargement automatique.

29voto

Mike Boers Points 3999

C'est ce que j'utilise dans tous mes projets (obtenus directement à partir de la source de la dernière):

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 regarde pour SomeClass_SeperatedWith_Underscores, il va chercher SomeClass_SeperatedWith_Underscores.php suivie par SomeClass/SeperatedWith/Underscores.php la racine de chaque répertoire dans le courant de chemin de.

EDIT: je voulais juste mis là-bas que je l'utiliser pour l'efficacité du développement, et pas forcément le temps de traitement. Si vous avez POIRE sur votre chemin puis avec cela, vous pouvez simplement utiliser les classes et n'ont pas à inclure lorsque vous en avez besoin.

J'ai tendance à garder mes classes dans une hiérarchie de répertoires, avec des traits de soulignement, à casser des espaces de noms... Ce code me permet de garder la structure du fichier agréable et bien rangé, si je veux, ou pour injecter rapidement un fichier de classe sans répertoires imbriqués si je veux (pour l'ajout d'une seule classe ou deux à une bibliothèque qu'il est défendeur, mais ne fait pas partie du projet, je suis en train de travailler.)

13voto

grossvogel Points 4562

J'ai atterri sur cette solution:

J'ai créé un script unique qui traverse ma bibliothèque de classe dossier (qui contient des sous-dossiers pour les modules séparés / systèmes), et analyse le contenu des fichiers à la recherche de définitions de classe. Si elle trouve une définition de classe dans un fichier php (assez simple expression régulière pattern), il crée un lien symbolique:

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

Cela me permet d'utiliser une simple fonction autoload qui a besoin seulement le nom de la classe et le chemin d'accès au principal, le lien symbolique du dossier, et n'a pas à faire tout le chemin/de manipulation de chaîne.

La meilleure partie est que je peux réorganiser mon code source entièrement ou en ajouter un nouveau sous-système et exécutez simplement le lien de génération de script pour avoir tout chargé.

9voto

jmucchiello Points 10521

Si vous voulez de l'efficacité, alors vous ne devriez pas être à l'aide de la fonction de chargement automatique à tous. La fonction de chargement automatique pour être paresseux. Vous devez fournir un chemin d'accès explicite à vos fichiers lorsque vous les inclure. Si votre fonction autoload pouvez trouver ces fichiers, alors vous pourriez le code pour trouver explicitement. Lorsque vous travaillez sur le point de vue de la partie du code et sur le point de charger un nouveau point de vue de classe, en laissant le chargement automatique de la fonction de la gérer, il suppose que la classe est une classe de modèle? C'est inefficace. Au lieu de votre code devrait être:

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

Si vous avez besoin de plusieurs "voir" les chemins, faire une fonction qui charge les points de vue:

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

En tout cas, au point où l'include se produit, vous avez le plus grand/plus d'information précise sur la catégorie que vous souhaitez charger. En utilisant cette information pour charger la classe pleinement est la seule efficace de chargement de classe de la stratégie. Oui, vous pouvez vous retrouver avec plus de variables de classe ou (à dieu ne plaise) des variables globales. Mais c'est un meilleur compromis que juste de la paresse et de la numérisation des pièces du système de fichiers pour votre classe.

0voto

thomasrutter Points 42905

J'ai une classe qui prend en charge, y compris, l'instanciation et l'initialisation des modules chargeables. Tous les modules chargeables hériter d'une classe de base commune. Une méthode de mon instantiator classe prend un nom de module comme argument, et peut dynamiquement comprennent que le fichier source du module, instancier un objet et de les initialiser. Par exemple, si le module est une partie de la "maquette" il est passé à l'DB objet. Alors que le nouvel objet est retourné.

À partir de controls.inc.php (ouais, c'est un peu PHP4-y).

class controls
{
    function &getcontrol($objecttype)
    {		
    	require_once(RESOURCE_DIR . "nodecontrols/$objecttype.inc.php");
    	$control = &new $objecttype($this->db);
    	return $control;
    }

    ...
}

Quand j'ai besoin d'instancier cet objet, je ne

$nodefetcher = $this->controls->getcontrol('nodefetcher');

$contrôles->getcontrol fait le travail de y compris le droit de fichier si il n'a pas déjà été (require_once), l'instanciation et de le transmettre à la DB de l'objet.

Les choses à surveiller:

  • Assurez-vous que l'entrée d'utilisateur ne peut pas empoisonner le chemin de l', par exemple en incluant des barres obliques et le chargement de fichiers, il ne devrait pas. Si nécessaire le filtre $objecttype de sorte qu'il peut contenir que des lettres et des chiffres, et de lever une exception si elle ne le fait pas.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X