46 votes

Chargement automatique des classes à partir de différents dossiers

C'est comme ça que je charge automatiquement toutes les classes de mon controllers dossier,

# auto load controller classes
    function __autoload($class_name) 
    {
        $filename = 'class_'.strtolower($class_name).'.php';
        $file = AP_SITE.'controllers/'.$filename;

        if (file_exists($file) == false)
        {
            return false;
        }
        include ($file);
    }

Mais j'ai des cours en models et je veux les charger automatiquement aussi - que dois-je faire ? Dois-je dupliquer l'autoload ci-dessus et changer le chemin en models/ (mais n'est-ce pas répétitif ??)?

Merci.

EDITAR:

Ce sont les noms des fichiers de mes classes dans le dossier du contrôleur :

class_controller_base.php
class_factory.php
etc

Ce sont les noms des fichiers de mes classes dans le dossier du modèle :

class_model_page.php
class_model_parent.php
etc

C'est ainsi que je nomme mes classes de contrôleurs en général (j'utilise des caractères de soulignement et des minuscules),

class controller_base 
{
...
}

class controller_factory
{
...
}

C'est ainsi que je nomme mes classes de modèles (j'utilise des caractères de soulignement et des minuscules),

class model_page 
    {
    ...
    }

    class model_parent
    {
    ...
    }

68voto

br3nt Points 640

Je vois que vous utilisez controller_***** y model_***** comme convention de dénomination des classes.

J'ai lu un fantastique article qui propose une convention de dénomination alternative en utilisant l'algorithme de php. namespace .

J'aime cette solution car l'endroit où je place mes classes n'a pas d'importance. Le site __autoload le trouvera, peu importe où il se trouve dans ma structure de fichiers. Cela me permet également d'appeler mes classes comme je le souhaite. Je n'ai pas besoin d'une convention de dénomination des classes pour que mon code fonctionne.

Vous pouvez, par exemple, configurer votre structure de dossiers comme suit :

  • application/
    1. Contrôleurs/
      • Base.php
      • Usine.php
    2. modèles/
      • Page.php
      • Parent.php

Vos classes peuvent être configurées comme suit :

<?php
namespace application\controllers;
class Base {...}

et :

<?php
namespace application\models;
class Page {...}

L'autochargeur pourrait ressembler à ceci (ou voir 'une note sur l'autochargeur' à la fin) :

function __autoload($className) {
    $file = $className . '.php';
    if(file_exists($file)) {
        require_once $file;
    }
}

Ensuite... vous pouvez appeler les classes de trois façons :

$controller = new application\controllers\Base();
$model = new application\models\Page();

ou,

<?php
use application\controllers as Controller;
use application\models as Model;

...

$controller = new Controller\Base();
$model = new Model\Page();

ou,

<?php
use application\controllers\Base;
use application\models\Page;

...

$controller = new Base();
$model = new Page();

EDIT - une note sur l'autoloading :

Mon chargeur automatique principal ressemble à ça :

// autoload classes based on a 1:1 mapping from namespace to directory structure.
spl_autoload_register(function ($className) {

    # Usually I would just concatenate directly to $file variable below
    # this is just for easy viewing on Stack Overflow)
        $ds = DIRECTORY_SEPARATOR;
        $dir = __DIR__;

    // replace namespace separator with directory separator (prolly not required)
        $className = str_replace('\\', $ds, $className);

    // get full name of file containing the required class
        $file = "{$dir}{$ds}{$className}.php";

    // get file if it is readable
        if (is_readable($file)) require_once $file;
});

Cet autoloader est une correspondance directe 1:1 du nom de la classe à la structure du répertoire ; l'espace de nom est le chemin du répertoire et le nom de la classe est le nom du fichier. Ainsi, la classe application\controllers\Base() défini ci-dessus chargerait le fichier www/application/controllers/Base.php .

Je place l'autoloader dans un fichier, bootstrap.php, qui se trouve dans mon répertoire racine. On peut soit l'inclure directement, soit modifier le fichier php.ini comme suit auto_prepend_file afin qu'il soit inclus automatiquement dans chaque demande.

En utilisant spl_autoload_register vous pouvez enregistrer plusieurs fonctions autoload pour charger les fichiers de classe comme vous le souhaitez. Par exemple, vous pouvez placer une partie ou la totalité de vos classes dans un seul répertoire, ou vous pouvez placer une partie ou la totalité de vos classes dans un seul répertoire. classes à espacement de noms dans un seul fichier . Très flexible :)

29voto

alex Points 186293

Vous devez nommer vos classes de manière à ce que le trait de soulignement ( _ ) se traduit par le séparateur de répertoire ( / ). Quelques frameworks PHP le font, comme Zend et Kohana.

Donc, vous nommez votre classe Model_Article et placez le fichier dans classes/model/article.php et ensuite votre autoload fait...

function __autoload($class_name) 
{
    $filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)).'.php';

    $file = AP_SITE.$filename;

    if ( ! file_exists($file))
    {
        return FALSE;
    }
    include $file;
}

Notez également que vous pouvez utiliser spl_autoload_register() pour faire de n'importe quelle fonction une fonction de chargement automatique. Il est également plus souple, puisqu'il vous permet de définir plusieurs fonctions de type autoload.

S'il doit y avoir plusieurs fonctions d'autoload, spl_autoload_register() le permet. Elle crée effectivement une file d'attente de fonctions d'autoload, et les exécute dans l'ordre où elles sont définies. En revanche, __autoload() ne peut être défini qu'une seule fois.

Modifier

Note : __autoload a été DÉPRECIÉ à partir de PHP 7.2.0. Il est fortement déconseillé de s'appuyer sur cette fonctionnalité. Veuillez consulter la documentation de PHP pour plus de détails. http://php.net/manual/en/function.autoload.php

7voto

DerDu Points 103

Je dois mentionner quelque chose à propos d'un "bon" scripts d'autoload et de la structure du code, alors lisez attentivement ce qui suit


Gardez à l'esprit :

  • Nom de classe \=== Nom de fichier
  • Seulement UNE classe par fichier

Par exemple Exemple.php contient

class Example {}
  • Espace de nommage \=== Structure du répertoire

Par exemple /Path1/Path2/Example.php correspond à

namespace Path1\Path2;
class Example {}
  • Il devrait y avoir un espace de nom racine pour éviter les collisions.

Par exemple /Path1/Path2/Example.php avec Root :

namespace APP\Path1\Path2;
class Example {}
  • N'utilisez JAMAIS de listes de chemins ou de répertoires définis manuellement, faites simplement pointer le chargeur vers le répertoire le plus haut.
  • Garder le chargeur aussi RAPIDE QUE POSSIBLE (car l'inclusion d'un fichier est déjà assez coûteuse).

Avec cela en tête, j'ai produit le script suivant :

function Loader( $Class ) {
    // Cut Root-Namespace
    $Class = str_replace( __NAMESPACE__.'\\', '', $Class );
    // Correct DIRECTORY_SEPARATOR
    $Class = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, __DIR__.DIRECTORY_SEPARATOR.$Class.'.php' );
    // Get file real path
    if( false === ( $Class = realpath( $Class ) ) ) {
        // File not found
        return false;
    } else {
        require_once( $Class );
        return true;
    }
}

Où le placer..

  • /Loader.php <-- voilà le chargeur
  • /Controller/... <-- mettez vos trucs ici
  • /Modèle/... <-- ou ici, etc
  • /...

Rappelez-vous :

  • si vous utilisez un espace de nom Root, le chargeur doit également se trouver dans cet espace de nom.
  • vous pouvez préfixer $Class pour répondre à vos besoins (controller_base {} -> class_controller_base.php)
  • vous pouvez changer __DIR__ en un chemin absolu contenant vos fichiers de classe (par exemple "/var/www/classes")
  • si vous n'utilisez pas les espaces de noms, tous les fichiers doivent être dans le même répertoire que le chargeur (mauvais !)

Bon codage ;-)


Un petit tour d'horizon des autres réponses : IL NE S'AGIT QUE DE MON OPINION PERSONNELLE - SANS VOULOIR VOUS OFFENSER !

https://stackoverflow.com/a/5280353/626731 @alex bonne solution, mais ne faites pas payer vos noms de classe pour de mauvaises structures de fichiers ;-) c'est le travail des espaces de noms

https://stackoverflow.com/a/5280510/626731 @Mark-Eirich ça marche, mais c'est plutôt désagréable/laids/lents/rigides[ ] style de le faire de cette façon .

https://stackoverflow.com/a/5284095/626731 @tealou pour que son problème soit résolu, c'est l'approche la plus claire jusqu'à présent :-) ..

https://stackoverflow.com/a/9628060/626731 @br3nt cela reflète mon point de vue, mais s'il vous plaît( !) n'utilisez pas strtr !! ce qui m'amène à :

https://stackoverflow.com/a/11866307/626731 @Iscariot pour vous, un petit "tu sais-bullshit-benchmark" :

Time        sprintf preg_replace strtr    str_replace v1 str_replace v2
08:00:00 AM 1.1334  2.0955       48.1423  1.2109         1.4819
08:40:00 AM 1.0436  2.0326       64.3492  1.7948         2.2337
11:30:00 AM 1.1841  2.5524       62.0114  1.5931         1.9200
02:00:00 PM 0.9783  2.4832       52.6339  1.3966         1.4845
03:00:00 PM 1.0463  2.6164       52.7829  1.1828         1.4981
Average     1.0771  2.3560       55.9839  1.4357         1.7237

Method         Times Slower (than sprintf)
preg_replace   2.19
strtr          51.97
str_replace v1 1.33
str_replace v2 1.6

Source : http://www.simplemachines.org/community/index.php?topic=175031.0

Des questions ? . (Mais il a en fait raison au sujet de l'inclusion du chemin complet)

https://stackoverflow.com/a/12548558/626731 @Sunil-Kartikey https://stackoverflow.com/a/17286804/626731 @jurrien

Ne jamais boucler dans un environnement où le temps est critique ! Ne cherchez pas de fichiers sur l'os ! - LENTEMENT

https://stackoverflow.com/a/21221590/626731 @sagits bien mieux que Marks ;-)

3voto

tealou Points 7136

Voici ma solution,

/**
     * autoload classes 
     *
     *@var $directory_name
     *
     *@param string $directory_name
     *
     *@func __construct
     *@func autoload
     *
     *@return string
    */
    class autoloader
    {
        private $directory_name;

        public function __construct($directory_name)
        {
            $this->directory_name = $directory_name;
        }

        public function autoload($class_name) 
        { 
            $file_name = 'class_'.strtolower($class_name).'.php';

            $file = AP_SITE.$this->directory_name.'/'.$file_name;

            if (file_exists($file) == false)
            {
                return false;
            }
            include ($file);
        }
    }

    # nullify any existing autoloads
    spl_autoload_register(null, false);

    # instantiate the autoloader object
    $classes_1 = new autoloader('controllers');
    $classes_2 = new autoloader('models');

    # register the loader functions
    spl_autoload_register(array($classes_1, 'autoload'));
    spl_autoload_register(array($classes_2, 'autoload'));

Je ne sais pas si c'est la meilleure solution ou non mais elle semble fonctionner parfaitement...

Qu'est-ce que tu en penses ?

2voto

sagits Points 188

Ma version de la réponse de @Mark Eirich :

    function myload($class) {
      $controllerDir = '/controller/';
      $modelDir = '/model/';
      if (strpos($class, 'controller') !== false) {              
        $myclass = $controllerDir . $class . '.php';
      } else {
        $myclass = $modelDir . $class . '.inc.php';
      }
          if (!is_file($myclass)) return false;
          require_once ($myclass);

    }

    spl_autoload_register("myload");

Dans mon cas, seules les classes de contrôleurs ont le mot clé dans leur nom, adaptez-le à vos besoins.

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