Analyse détaillée du mécanisme de chargement automatique en PHP

Source : Internet
Auteur : utilisateur
__Autoload mise en œuvre de chargement automatique, mais en raison de la mise en place de bibliothèques de classes multiples, __autoload entretien sera complexe, l’introduction de SPL_AOTOLOAD, SPL pour mettre en place une liste de chargement automatique fonction enregistrement manuel et l’enlèvement, nous allons jeter un oeil à la teneur précise.

PHP avant que la méthode magique fonction __autoload apparaît, si vous souhaitez instancier 100 objets dans un fichier de programme, vous devez inclure la classe 100 fichiers inclus ou besoin, ou vous définissez ces 100 classes dans le même fichier de classe-- On croit que ce document soit très grand. Mais la méthode __autoload sort et vous n’aurez pas à vous inquiéter à ce sujet dans le futur, et cette classe se charge automatiquement le fichier développé avant d’instancier l’objet.

1. présentation générale du mécanisme AutoLoad

Lors du développement d’un système utilisant le mode OO de PHP, il est souvent d’usage pour stocker la mise en œuvre de chaque classe dans un fichier séparé, ce qui le rend facile de réutiliser des classes et qui est commode pour l’entretien futur. C’est aussi une des idées fondamentales de conception OO. Avant PHP5, si vous avez besoin d’utiliser une classe, il suffit utiliser Include / demander directement de le pour inscrire. Ce qui suit est un exemple concret :

/* Person.class.php */<?php class Person {  var $name, $age;    function __construct ($name, $age)  {   $this->name = $name;   $this->age = $age;  } }?>/* no_autoload.php */<?php require_once (”Person.class.php”);  $person = new Person(”Altair”, 6); var_dump ($person);?>

Dans cet exemple, le fichier non-autoload.php nécessite l’utilisation de la classe person, qui utilise le require_once pour l’integrer et peut alors être utilisée directement pour instancier un objet.

Mais comme l’ampleur du projet continue de croître, il y a quelques problèmes implicites avec l’aide de cette approche : si un fichier PHP a besoin d’utiliser de nombreuses autres classes, beaucoup de besoin/incluent les déclarations sont nécessaires, qui peuvent causer des omissions ou inclure des fichiers de classe inutiles. Si un grand nombre de fichiers requièrent l’utilisation d’autres classes, c’est certainement un cauchemar pour s’assurer que chaque fichier contient les fichiers de classe correcte.

PHP5 offre une solution à ce problème, qui est le mécanisme de chargement automatique (chargement automatique) de la classe. Le mécanisme de chargement automatique permet aux programmes PHP inclure automatiquement les fichiers de classe lors de l’utilisation des classes, plutôt qu’y compris classe tous les fichiers en premier lieu, un mécanisme connu sous le nomChargement différé

Voici un exemple d’une classe person en utilisant le mécanisme de chargement automatique de chargement :

/* autoload.php */<?php function __autoload($classname){  $classpath="./".$classname.'.class.php';  if(file_exists($classpath))  {    require_once($classpath);  }  else  {    echo 'class file'.$classpath.'not found!';   }}  $person = new Person(”Altair”, 6); var_dump ($person); ?>

Généralement PHP5 lorsque vous utilisez une classe, s’il est constaté que la classe n’est pas chargée, la fonction __autoload s’exécute automatiquement, dans lequel nous pouvons charger les classes qui doivent être utilisés. Dans notre exemple simple, nous ajoutons directement le nom de classe à l’extension «. class.php » pour former le nom de fichier de classe, puis utilisez require_once pour le charger. Dans cet exemple, nous pouvons voir queChargement automatiqueIl y a au moins trois deux choses à faire,La première chose est de déterminer le nom de fichier de classe basé sur le nom de classe, et la deuxième chose est de déterminer le chemin d’accès de disque où se trouvent les fichiers de classe (dans notre exemple, le cas le plus simple, la classe est sous le même dossier que le fichier de programme PHP qui les appelle), et la troisième chose est de charger la classe dans le fichier de disque dans le système.La troisième étape est la plus simple, seule l’utilisation d’Include / nécessitent peut être. Pour mettre en oeuvre la première étape, la deuxième étape de la fonction, il faut développer au moment du nom de classe de contrat et de la méthode de mappage de fichier disque, alors seulement nous pouvons trouver son fichier de disque correspondant selon le nom de la classe.

Donc, quand il y a un grand nombre de fichiers de classe à, il suffit de déterminer les règles correspondantes, et ensuite dans la fonction __autoload, le nom de la classe correspond au fichier disque réel, vous pouvez obtenir l’effet de chargement différé. De là, nous pouvons également voir que la chose la plus importante dans la mise en œuvre de la fonction __autoload() est la mise en œuvre de la nom de la classe et la règle de mappage de fichier disque réel.

Mais maintenant le problème est que si dans la mise en œuvre d’un système, si vous avez besoin d’utiliser beaucoup d’autres bibliothèques de classes, ces bibliothèques de classes peuvent être écrit par des programmeurs différents, leurs noms de classes et les fichiers de disque réellement les règles de mappage sont différents. À ce stade, si vous souhaitez implémenter le chargement automatique des fichiers de bibliothèque de classes, vous devez implémenter toutes les règles de mappage dans la fonction __autoload, afin que la fonction __autoload peut être très complexe ou même impossible à mettre en œuvre. Enfin, la fonction __autoload peut-être être très gonflée, et même si c’est possible, il aura une incidence négative sur l’entretien futur et l’efficacité du système. Dans ce cas, y at-il pas plus simple et plus clair solution ? La réponse, bien sûr : non ! Avant d’examiner plus de solutions, prenons un coup d’oeil à la façon dont le mécanisme de chargement automatique en PHP est mis en œuvre.

2. la mise en œuvre du mécanisme de chargement automatique de PHP

Nous savons que l’exécution des fichiers PHP se divise en deux processus distincts, la première étape consiste à compiler le fichier PHP dans ce qui est communément appeléOPCODESéquence de code octet (effectivement compilé dans un tableau d’octets nommé Zend_op_array), et la deuxième étape consiste à exécuter ces OPCODE par une machine virtuelle. Tout comportement de PHP est mis en œuvre par ces OPCODE. Par conséquent, afin d’étudier le mécanisme de mise en œuvre de chargement automatique en PHP, nous compiler le fichier autoload.php dans opcode et alors basé sur ces OPCODE pour étudier ce que PHP a fait dans ce processus :

/ * Autoload.php la liste compilée de OPCODE, qui est générée à l’aide de l’outil OPDUMP * développé par l’auteur, peut être téléchargé sur le téléchargement de http://www.phpinternals.com/to site Web du logiciel.    * / 1 : &lt; ? php 2 : / / Require_once (« Person.php ») ;    III : 4 : fonction __autoload ($classname) {RECV de NOP 0 0 5 1 : Si ( ! class_exists ($classname)) {1 Send_var ! 0 2 do_fcall ' class_exists ' [Extval:1] 3 BOOL_NOT $0 = &gt; RES [1] 4 JMPZ ~ 1 -&gt; 8 6:re Quire_once ($classname.            «. Class.php ») ;            CONCAT 5 ! 0, '. class.php ' = &gt; RES [2] INCLUDE_OR_EVAL 6 ~ 2, REQUIRE_ONCE 7 :} JMP sept -&gt; 8 8 :} 8 retourner null 09:10 : $p = new Person ("Fred            35) ; 1 FETCH_CLASS « personne » = &gt; RES [ : 0] 2 NEW : 0 = &gt; RES [$1] 3 SEN D_VAL « Fred » 4 SEND_VAL 5 DO_FCALL_BY_NAME [Extval:2] 6 A            Ssigner ! 0, $11 : 12:var_dump ($p) ; 7 SEND_VAR ! 0 8 DO_FCALL « var_dump » [extval:1] : ? &gt;

Dans la ligne 10 de autoload.php code, nous avons besoin d’instancier un objet pour la personne de la classe. Par conséquent, le mécanisme de chargement automatique figurera certainement dans l’opcode compilé de la ligne. De l’OPCODE généré en ligne 10 ci-dessus, nous savons que lorsque vous instanciez une objet une personne, vous exécutez d’abord la directive FETCH_CLASS. Nous commençons notre voyage d’exploration du processus de transformation de PHP de la directive FETCH_CLASS.

En consultant le code source de PHP (j’utilise la version PHP 5.3ALPHA2), vous pouvez trouver la séquence suivante d’appels :

ZEND_VM_HANDLER (A, ZEND_FETCH_CLASS,...) (Lignes Zend_vm_def.h 1864) = > Zend_fetch_class (lignes zend_execute_API.c 1434) = > ZEND_LOOKUP_CLASS_EX (zend_execute_API.c lignes de 964) = > zend_call_function (& fcall_info, & fcall_cache) (lignes zend_execute_API.c 1040)

Avant d’appeler la dernière étape, nous allons regarder les paramètres clés au moment de l’appel :

/ * Valeur de variable d’autoload_function de */fcall_info.function_name « __autoload » = Ooops, a enfin trouvé « __autoload »... Fcall_cache.function_handler = EG (Autoload_func) ; Autoload_func !

Zend_call_functionEst l’une des fonctions plus importantes dans le Zend Engine, dont la fonction principale est d’exécuter les fonctions que l’utilisateur a personnalisé le programme PHP ou la fonction de bibliothèque de PHP lui-même. Zend_call_function a deux paramètres importants en forme de pointeur fcall_info, Fcall_cache, qui pointent vers deux structures importantes, un zend_fcall_info et l’autre est Zend_fcall_info_cache. Le flux de travail principal de Zend_call_function est la suivante : si le pointeur de la Fcall_cache.function_handler a la valeur NULL, essayer de trouver une fonction nommée Fcall_info.function_name, si elle existe, Exécute ; si le Fcall_cache.function_handler n’est pas NULL, la fonction à laquelle les points de Fcall_cache.function_handler est exécuté directement.

Maintenant, nous savons que lorsque PHP instancie un objet (en fait, lorsque vous implémentez une interface, en utilisant une constante de classe ou d’une variable static dans une classe, appeler une méthode statique dans une classe), il abord apprend si la classe (ou interface) existe dans le système et tente de charger la classe en utilisant le mécanisme de chargement automatique s’il n’existe pas. Le processus d’exécution principal du mécanisme de chargement automatique est comme :

  1. Vérifiez que la variable globale actionneur fonction pointeur autoload_func est NULL.

  2. Si autoload_func == NULL, savoir si la fonction __autoload est définie dans le système et si pas, signaler l’erreur et la sortie.

  3. Si la fonction __autoload est définie, le __autoload () est exécutée pour tenter de charger la classe et retourner le résultat de la charge.

  4. Si l’autoload_func n’est pas NULL, la fonction à laquelle les points de pointeur Autoload_func est exécuté directement est utilisée pour charger la classe. Remarque cela ne vérifie pas que la fonction __autoload est définie.

La vérité est enfin blanche, PHP fournit deux méthodes pour implémenter le mécanisme de chargement automatique, nous l’avons déjà mentionné, consiste à utiliser la fonction __autoload défini par l’utilisateur, qui est généralement mis en œuvre dans le programme source PHP, l’autre est de concevoir une fonction, pointez dessus, le pointeur de l’autoload_func Ceci est généralement implémenté dans les extensions PHP en utilisant le langage C. Si vous implémentez la fonction __autoload tant la Autoload_func (qui désigne une fonction PHP autoload_func), seule la fonction Autoload_func est exécutée.

3. réalisation du mécanisme de chargement automatique SPL

SPL est une abréviation pour standard PHP Library C’est une bibliothèque d’extension présentée par PHP5, dont les fonctions principales comprennent la mise en œuvre du mécanisme de chargement automatique et y compris les diverses interfaces itérateur ou classes. La mise en œuvre du mécanisme de SPL AutoLoad est obtenue en pointant l’autoload_func de pointeur de fonction à la fonction avec la fonction de chargement automatique mis en place par lui-même. SPL a deux fonctions différentes spl_autoload, Spl_autoload_call, pour mettre en œuvre différents mécanismes de chargement automatique en faisant autoload_func à ces deux adresses de fonction différente.

Spl_autoload est la fonction de charge automatique par défaut mis en œuvre par SPL, et sa fonction est relativement simple. Il peut recevoir deux paramètres, le premier paramètre est $class_name, qui représente le nom de classe, le second paramètre $file_extensions est facultatif, ce qui représente l’extension de fichier de classe, vous pouvez spécifier plusieurs extensions dans le $file_extensions et le nom complet est séparé par un point-virgule Si non spécifié, il utilisera la valeur par défaut extension. Inc. OR. php. Spl_autoload change tout d’abord le $class_name en minuscules, et puis cherche les fichiers $class_name.inc ou $class_name.php en tout chemin d’accès include (si vous ne spécifiez pas le paramètre $file_extensions ), Si trouvé, charge le fichier de classe. Vous pouvez utiliser manuellement Spl_autoload (« personne », «. class.php ») pour charger la classe person. En fait, c’est le même que nécessitent/include, et contrairement à elle, elle peut spécifier plusieurs extensions.

Comment faites-vous spl_autoload fonctionne automatiquement, autrement dit, point Autoload_func pour Spl_autoload ? La réponse est d’utiliser la fonction Spl_autoload_register. Si vous appelez Spl_autoload_register () pour la première fois dans un script PHP sans utiliser de paramètres, vous pouvez pointer Autoload_func vers Spl_autoload.

Comme nous le savons depuis les instructions ci-dessus, fonctionnalité de Spl_autoload est relativement simple et il est implémenté dans les extensions SPL, et nous ne pouvons pas étendre ses fonctionnalités. Que se passe-t-il si vous souhaitez implémenter votre propre mécanisme de chargement automatique plus souple ? À ce stade, la fonction Spl_autoload_call brille sur la scène.

Nous allons jeter un oeil à ce qui est merveilleux sur la réalisation de spl_autoload_call. L’intérieur du module SPL, il y a une variable globale, autoload_functions, qui est essentiellement une table de hachage, mais on le voit tout simplement comme une liste chaînée, et chaque élément dans la liste est un pointeur de fonction à une fonction avec la possibilité de charger automatiquement les classes. La mise en œuvre de la Spl_autoload_call elle-même est simple, tout simplement l’exécution de chaque fonction dans la liste dans l’ordre, déterminer si la classe requise a été chargée après que chaque fonction se termine et retournant directement si le chargement a réussi, n’est plus continue d’exécuter d’autres fonctions dans la liste. Si toutes les fonctions dans cette liste sont remplies après que la classe n’a pas été chargée, spl_autoload_call quitte directement et ne signale pas les erreurs à l’utilisateur. Par conséquent, l’utilisation du mécanisme de chargement automatique, il n’y a aucune garantie que la classe sera en mesure de charger correctement, la clé est de voir comment votre fonction de chargement automatique est mis en œuvre.

Alors, qui est autoload_functions de maintenir la liste de fonction automatique de la charge ? La fonction Spl_autoload_register est mentionnée. Il peut s’inscrire à une fonction de chargement automatique défini par l’utilisateur dans cette liste et le point le AUTOLOAD_FUNC fonction pointeur vers la fonction Spl_autoload_call (Notez qu’il existe une exception affaire, qui est exactement ce qu’il reste à chacun de réfléchir). Nous pouvons également supprimer une fonction inscrite dans la liste Autoload_functions par le biais de la fonction Spl_autoload_unregister.

Comme mentionné dans la section précédente, lorsque le pointeur de la Autoload_func n’est pas vide, la fonction __autoload ne s’exécute pas automatiquement, et maintenant Autoload_func a souligné spl_autoload_call, si nous voulons encore laisser __autoload) Que doit faire une fonction quand ça marche ? Bien sûr, utilisez l’appel Spl_autoload_register (__autoload) pour inscrire dans la liste des Autoload_functions.

Maintenant, retour à la dernière question dans la première section, nous avons une solution : mettre en œuvre leurs propres fonctions de chargement automatique basées sur différents mécanismes d’affectation de noms pour chaque bibliothèque de classes et ensuite utiliser Spl_autoload_register pour enregistrer dans la file d’attente SPL chargement automatique fonction, respectivement. Ainsi nous n’avons pas de maintenir une fonction __autoload très complexe.

4. contre-mesures et les problèmes d’efficacité autoLoad

Lorsque vous utilisez le mécanisme de chargement automatique, la première réaction de beaucoup de gens est à chargement automatique permet de réduire l’efficacité du système, et même quelqu'un propose tout simplement ne pas d’utiliser autoload pour l’efficacité. Après que nous comprenons les principes de mise en œuvre de chargement automatique, nous savons que le mécanisme de chargement automatique elle-même n’est pas la cause de l’efficience du système, ou même qu’il peut améliorer l’efficacité du système car il ne charge pas de classes non désirées dans le système.

Alors pourquoi beaucoup de gens ont l’impression que l’utilisation d’autoload réduira l’efficacité du système ? En fait, l’efficacité qui affecte le mécanisme de chargement automatique elle-même est précisément la fonction de chargement automatique conçue par l’utilisateur. Si elle ne correspond pas efficacement le nom de classe dans le fichier de disque réel (Notez que cela s’applique au fichier disque réel, pas seulement le nom du fichier), le système devra faire beaucoup de jugements sur la question de savoir si le fichier existe (qui doit être recherchée dans le chemin d’accès contenus dans chaque chemin d’accès include), Et pour déterminer si le fichier existe devez faire opération e/s de disque, il est bien connu que l’efficacité d’opération I/O disque est très faible, alors c’est le mécanisme de chargement automatique pour réduire l’efficacité du coupable !

Par conséquent, lorsque nous concevons le système, nous devons définir un ensemble clair de mécanismes pour mapper le nom de classe dans le fichier disque réel. Le plus efficace, le plus simple et plus claire de que cette règle est le mécanisme de chargement automatique est.

Conclusion : Le mécanisme de chargement automatique n’est pas une inefficacité naturelle, seulement l’abus d’AutoLoad, la conception de la fonction de chargement automatique conduira à son efficacité réduite.

Article associé

Nous contacter

Le contenu de cette page provient d'Internet et ne reflète pas l'opinion d'Alibaba Cloud ; les produits et services mentionnés sur cette page n'ont aucune relation avec Alibaba Cloud. Si le contenu de la page vous semble problématique, veuillez nous écrire un courriel, nous traiterons le problème dans les 5 jours suivant la réception de votre message.

Si vous constatez des cas de plagiat de la part de la communauté, veuillez envoyer un courriel à : info-contact@alibabacloud.com et fournir des preuves pertinentes. Un membre de notre équipe vous contactera dans les 5 jours ouvrables.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.