Qu'est-ce que le chargement automatique; Comment utilisez-vous spl_autoload, __autoload et spl_autoload_register?


204

J'apprends des normes PHP avancées et j'essaye d'implémenter de nouvelles méthodes utiles. Auparavant, j'utilisais __autoloadjuste pour échapper, y compris plusieurs fichiers sur chaque page, mais récemment, j'ai vu une astuce sur__autoload manual

spl_autoload_register () fournit une alternative plus flexible pour les classes de chargement automatique. Pour cette raison, l'utilisation de __autoload () est déconseillée et peut être déconseillée ou supprimée à l'avenir.

mais je ne peux vraiment pas comprendre comment mettre en œuvre spl_autoloadetspl_autoload_register

Réponses:


335

spl_autoload_register() vous permet d'enregistrer plusieurs fonctions (ou méthodes statiques de votre propre classe Autoload) que PHP mettra dans une pile / file d'attente et appellera séquentiellement lorsqu'une "nouvelle classe" sera déclarée.

Ainsi, par exemple:

spl_autoload_register('myAutoloader');

function myAutoloader($className)
{
    $path = '/path/to/class/';

    include $path.$className.'.php';
}

//-------------------------------------

$myClass = new MyClass();

Dans l'exemple ci-dessus, "MyClass" est le nom de la classe que vous essayez d'instancier, PHP transmet ce nom sous forme de chaîne à spl_autoload_register() , ce qui vous permet de récupérer la variable et de l'utiliser pour "inclure" la classe / le fichier approprié . Par conséquent, vous n'avez pas besoin spécifiquement d'inclure cette classe via une instruction include / require ...

Appelez simplement la classe que vous souhaitez instancier comme dans l'exemple ci-dessus, et puisque vous avez enregistré une fonction (via spl_autoload_register() ) de votre choix qui déterminera où se trouve toute votre classe, PHP utilisera cette fonction.

L'avantage de l'utilisation spl_autoload_register()est que, contrairement à __autoload()vous, vous n'avez pas besoin d'implémenter une fonction de chargement automatique dans chaque fichier que vous créez. spl_autoload_register()vous permet également d'enregistrer plusieurs fonctions de chargement automatique pour accélérer le chargement automatique et le rendre encore plus facile.

Exemple:

spl_autoload_register('MyAutoloader::ClassLoader');
spl_autoload_register('MyAutoloader::LibraryLoader');
spl_autoload_register('MyAutoloader::HelperLoader');
spl_autoload_register('MyAutoloader::DatabaseLoader');

class MyAutoloader
{
    public static function ClassLoader($className)
    {
         //your loading logic here
    }


    public static function LibraryLoader($className)
    {
         //your loading logic here
    }

En ce qui concerne spl_autoload , le manuel indique:

Cette fonction est destinée à être utilisée comme implémentation par défaut pour __autoload(). Si rien d'autre n'est spécifié et spl_autoload_register()est appelé sans aucun paramètre, ces fonctions seront utilisées pour tout appel ultérieur à __autoload().

En termes plus pratiques, si tous vos fichiers se trouvent dans un seul répertoire et que votre application utilise non seulement des fichiers .php, mais des fichiers de configuration personnalisés avec des extensions .inc par exemple, alors une stratégie que vous pourriez utiliser serait d'ajouter votre répertoire contenant tous les fichiers vers le chemin d'inclusion de PHP (via set_include_path()).
Et puisque vous avez également besoin de vos fichiers de configuration, vous utiliseriez spl_autoload_extensions()pour répertorier les extensions que vous souhaitez que PHP recherche.

Exemple:

set_include_path(get_include_path().PATH_SEPARATOR.'path/to/my/directory/');
spl_autoload_extensions('.php, .inc');
spl_autoload_register();

Puisque spl_autoload est l'implémentation par défaut de la __autoload()méthode magique, PHP appellera spl_autoload lorsque vous essayez d'instancier une nouvelle classe.

J'espère que cela t'aides...


35
C'est peut-être l'une des meilleures réponses de l'histoire des réponses. Le respect. J'avais un de ces "OMG! Tout a du sens maintenant!" moments à cause de vous, mon brave homme. Je pense que je pourrais juste créer un fan club.
Just Plain High

2
Pour en faire la meilleure réponse de toutes les réponses, même dans des univers alternatifs, veuillez ajouter que spl_autoload très, euh, "utilement" (?) Convertit tous les noms de fichiers en minuscules (voir mon commentaire à @user ci-dessous). Impossible d'utiliser spl_autoload_register () vanilla si vous aimez votre CapitalLettersAndStuff.
Just Plain High

6
@Just Plain High Je n'ai pas ce problème et tous mes fichiers de classe sont camelcasés. BTW, c'est une merveilleuse réponse. Cela m'a aidé à comprendre un concept simple que je ne pouvais tout simplement pas comprendre avant d'avoir lu ce post! Ma ligne 85 (et en pleine croissance) inclut un fichier qui comprend tous mes fichiers de classe est maintenant 7 lignes!
kyle

2
C'est en effet une bonne réponse mais il me manque une chose. Quelle est la fonctionnalité par défaut réelle? Avec les classes que je connais, il utilise l'espace de noms comme chemin et le nom de classe comme nom de fichier. Bien que je ne puisse pas comprendre comment cela fonctionne avec les fonctions.
SiXoS

2
N'est-ce pas l'un des énormes avantages à utiliser spl_autoload_register()(et __autoload()en général) que les charges paresseuses incluent les fichiers / classes? Cela est implicite dans la réponse, mais pas explicitement indiqué. Pour moi, ce sont des informations essentielles qui seraient parfaites pour être incluses dans votre réponse! :)
rinogo

13

Depuis PHP 5.3, vous pouvez utiliser spl_autoload_register()avec des espaces de noms, ce qui signifie que vous pouvez organiser votre projet et charger automatiquement vos classes php sans aucune exigence ou inclusion et sans redéfinir une __autoload()fonction.

Pour illustrer ce comportement, créez simplement un fichier appelé index.php:

<?php
spl_autoload_register();
var_dump(new Main\Application);

Créez ensuite un dossier nommé Main situé juste à côté du fichier index.php. Enfin, crée un fichier appelé Application.php situé dans Main et collez-y le code suivant:

<?php namespace Main;
class Application{}

9
Une note de mon tripotage avec tout cela: spl_autoload () - et donc spl_autoload_register () - convertit les noms de fichiers en minuscules (malgré les rapports de bogues, les appels et les votes furieux). Cela signifie que vous recherchez peut-être "Main \ Application" mais spl_autoload recherche "main \ Application". Si vous aimez les chameaux, comme moi, vous devrez écrire votre propre fonction. Il y a un bel exemple de démarrage ici: github.com/ircmaxell/PHP-CryptLib/blob/…
Just Plain High

1
Pour: spl_autoload_register () est la méthode la plus rapide de chargement automatique Contre: elle ne fonctionnera qu'avec des fichiers / classes en minuscules et des espaces de noms aussi, qui à l'heure actuelle ne sont que très gros (aucune option pour lui dire d'utiliser CamelCase, etc.). Mais si vous pouvez vivre avec la structure namespace / classname.php, ne cherchez plus.
stamster

1
spl_autoload_register()l'implémentation par défaut ne parvient pas à trouver les classes héritées. Donc, en utilisant les valeurs par défaut, les fichiers en minuscules et les répertoires reflétant le chemin de l'espace de noms, tout fonctionne bien, sauf si j'ai une classe qui étend une autre classe (parent). PHP lance ensuite une erreur selon laquelle il ne peut pas trouver cette classe parente, même s'ils sont tous dans le même répertoire / espace de noms! Ce qui est déroutant, c'est que seules les classes de premier niveau sont littéralement trouvées, j'ai donc dû en mettre une autre spl_autoload_register()avec une règle de fonction anonyme juste après la première pour pouvoir inclure manuellement les classes parent / héritées manquantes.
stamster

1

Voici comment j'utilise le chargement automatique. Dans l'exemple donné, je veux charger les classes de 3 répertoires différents.

function namespaceAutoload($rawClass){

$class = str_replace('\\', DIRECTORY_SEPARATOR, $rawClass);

$possiblePaths[] = '..\sys\class\file.php';
$possiblePaths[] = '..\sys\class\lib\file.php';
$possiblePaths[] = '..\sys\class\class.file.inc.php';

foreach ($possiblePaths as $templatePath) {
    $path = str_replace(["\\", "file"], [DIRECTORY_SEPARATOR, $class], $templatePath);
    if (file_exists($path)) {
        require_once "$path";
        break;
    }
} spl_autoload_register("namespaceAutoload"); 

Dans l'exemple donné, le PHP recherchera l'espace de noms \ classe dans ces trois répertoires en utilisant ces trois formats de nom de fichier différents.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.