"Cet article présente principalement le processus d'exécution du framework
"
Si vous ne savez pas comment le framework est exécuté, alors la majeure partie du code consiste simplement à comprendre le code. Lire le code source consiste à apprendre les idées de conception. et les modèles de code du framework.
Le processus d'exécution consiste à relier les choses que nous apprenons ensemble pour mieux comprendre. Kaka dessinera également pour vous le processus d'exécution sous la forme d'une carte mentale.
Tant que tout le monde apprendra un peu de connaissances grâce à cet article, Kaka sera satisfait.
Cet organigramme concerne uniquement le processus d'exécution d'initialisation. Le reste du processus d'exécution sera complété ultérieurement et sera présenté à chacun sous forme de cartes mentales.
Le contenu ici est un peu répétitif avec le contenu du conteneur, car le processus d'exécution commence à partir du fichier d'entrée et est finalement exécuté via le conteneur.
entrera alors la méthode d'exécution du fichier thinkphp/library/think/App.php
Dans cette méthode, la méthode d'initialisation est exécutée principalement à l'endroit indiqué dans le cadre ci-dessous.
En ce qui concerne la méthode d'initialisation, regardons d'abord la première moitié.
microtime(true);
Renvoie le nombre de microsecondes sous Unixmemory_get_usage
Renvoie la quantité de mémoire allouée à PHP en unités d'octets static::setInstance($this);
Voici comment définir l'instance d'application en tant que conteneur Exemple $this->instance('app', $this);
Cela a été mentionné dans le chapitre sur le conteneur auparavant, afin de lier la classe d'application au conteneur, qui est le mode arbre d'enregistrement. Voici un petit problème pour tout le monde. Il existe dans cette méthode d'initialisation de l'application. ligne de code.
Quelqu'un a-t-il des doutes à propos de cet $this->env
et des $this->config
appels suivants ?
Si vous avez des doutes, suivez simplement Kaka et lisez-le. Si vous n'avez aucun doute, vous pouvez continuer à lire.
La classe App est une classe conteneur héritée, donc env et config n'ont pas ces deux attributs ni dans l'application ni dans la classe conteneur.
Alors comment peut-on l'appeler directement ? Et le suivi du code sera retracé jusqu'à la classe env et la classe conteneur.
Pour connaître la source, nous devons jeter un coup d'œil au code de la classe conteneur.
Après une lecture difficile, vous pouvez voir quelques lignes de code dans l'image ci-dessous. Ces lignes de code utilisent toutes des méthodes magiques.
Lorsque la classe env accédée n'existe pas, la méthode make sera exécutée.
La méthode make est si détaillée dans le chapitre sur les conteneurs qu'elle ne peut pas être expliquée en détail.
Cette méthode make renverra éventuellement une instance de la classe et la stockera dans le conteneur.
Mettez ici uniquement le code d'une méthode make. Si vous ne savez pas comment faire, vous pouvez lire l'article précédent.
La dernière étape consiste à charger une série de données. Veuillez consulter la carte mentale dans la préface pour les détails du chargement.
Dans le processus de lecture du code source, un problème difficile à contrôler est qu'une méthode est appelée à différents endroits, mais on ne la connaît pas du tout pendant un moment . Où s'appelle-t-il.
Voici une démonstration utilisant la méthode init.
La méthode init est une méthode pour initialiser une application ou un module, mais le paramètre module ici a une valeur nulle.
Créez d'abord un point d'arrêt pour vérifier les informations de données pertinentes.
Le résultat imprimé est vide. C'est une erreur que feront certains nouveaux partenaires d'apprentissage, car cette méthode ne peut pas être appelée une seule fois.
Si les modules d'initialisation sont tous vides, alors cette méthode n'a pas besoin d'exister.
Alors la méthode de point d'arrêt correcte devrait être comme ceci.
Il y aura un problème à ce moment-là. Cette méthode init est évidemment appelée deux fois, alors où est l'autre appel !
Si vous ne connaissez pas la nouvelle technique, vous imprimerez une série de points d'arrêt pour voir où l'exécution est effectuée, comme l'impression au niveau supérieur de l'initialisation.
C'est-à-dire imprimer des points d'arrêt dans la méthode d'initialisation, mais cela est très gênant, et cela risque de perdre beaucoup de temps et de ne toujours pas trouver le bon endroit.
Conseils : debug_backtrace()
Cette méthode générera une trace arrière, qui affichera tous les emplacements d'appel d'une méthode.
L'utilisation est celle indiquée ci-dessous. Il vous suffit d'imprimer la méthode debug_backtrace.
Sur la base des informations obtenues sur les données, le positionnement peut être effectué très rapidement.
La première fois, c'est sur la ligne 215 de la classe app.
La deuxième fois est à la ligne 60 de la thinkphp/library/think/route/dispatch/Module.php
classe
Vous pouvez faire une impression ici pour voir si ce module est index
Nous avons donc cette méthode pour localiser le lieu d'appel très rapidement.
Ce qui précède vous fournit une petite astucedebug_backtrace
Une démonstration pratique de la façon de vérifier où une méthode est exécutée.
Et le cas utilise également la méthode init pour démontrer, car la prochaine étape consiste à avoir une compréhension approfondie de la méthode init.
Les principales choses effectuées dans la méthode init ont été clairement décrites dans la carte mentale ci-dessus.
bindTo
dans la classe conteneur pour l'enregistrement de liaison. env
Configuration des variables d'environnement<span style="display: block; background: url(https://files.mdnice.com/point.png); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * 初始化应用或模块<br/> * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@access</span> public<br/> * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@param</span> string $module 模块名<br/> * <span class="hljs-doctag" style="color: #c678dd; line-height: 26px;">@return</span> void<br/> */</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">public</span> <span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">function</span> <span class="hljs-title" style="color: #61aeee; line-height: 26px;">init</span><span class="hljs-params" style="line-height: 26px;">($module = <span class="hljs-string" style="color: #98c379; line-height: 26px;">''</span>)</span><br/> </span>{<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 定位模块目录</span><br/> $module = $module ? $module . DIRECTORY_SEPARATOR : <span class="hljs-string" style="color: #98c379; line-height: 26px;">''</span>;<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * 第一次:D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\<br/> * 第二次:D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\<br/> */</span><br/> $path = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->appPath . $module;<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载初始化文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>;<br/> } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">elseif</span> (is_file(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->runtimePath . $module . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->runtimePath . $module . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'init.php'</span>;<br/> } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">else</span> {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载行为扩展文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'tags.php'</span>)) {<br/> $tags = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'tags.php'</span>;<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_array($tags)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->hook->import($tags);<br/> }<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载公共文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'common.php'</span>)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include_once</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'common.php'</span>;<br/> }<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-string" style="color: #98c379; line-height: 26px;">''</span> == $module) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载系统助手函数</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->thinkPath . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'helper.php'</span>;<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 加载中间件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'middleware.php'</span>)) {<br/> $middleware = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'middleware.php'</span>;<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_array($middleware)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->middleware->import($middleware);<br/> }<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 注册服务的容器对象实例</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_file($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'provider.php'</span>)) {<br/> $provider = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">include</span> $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'provider.php'</span>;<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_array($provider)) {<br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->bindTo($provider);<br/> }<br/> }<br/><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * $path : "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\"<br/> * "D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\application\index\"<br/> */</span><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 自动读取配置文件</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (is_dir($path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'config'</span>)) {<br/> $dir = $path . <span class="hljs-string" style="color: #98c379; line-height: 26px;">'config'</span> . DIRECTORY_SEPARATOR;<br/> } <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">elseif</span> (is_dir(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->configPath . $module)) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// D:\phpstudy_pro\WWW\ThinkPHPSourceCodeAnalysis\config\</span><br/> $dir = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->configPath . $module;<br/> }<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// scandir:以升序的方式读取目录中的文件</span><br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 返回就是config目录中的所有文件</span><br/> $files = <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">isset</span>($dir) ? scandir($dir) : [];<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">foreach</span> ($files <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">as</span> $file) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * $this->configExt:配置文件的后缀<br/> * pathinfo返回的是文件后缀,关于pathinfo共有三个可选的参数PATHINFO_DIRNAME、PATHINFO_BASENAME、PATHINFO_EXTENSION,分别为只返回文件名,文件目录名,文件扩展<br/> */</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> (<span class="hljs-string" style="color: #98c379; line-height: 26px;">'.'</span> . pathinfo($file, PATHINFO_EXTENSION) === <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->configExt) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">/**<br/> * 俩个参数分别为<br/> * 1.目录+config目录下的文件<br/> * 2.config目录下文件名<br/> */</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->config->load($dir . $file, pathinfo($file, PATHINFO_FILENAME));<br/> }<br/> }<br/> }<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->setModulePath($path);<br/><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span> ($module) {<br/> <span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">// 对容器中的对象实例进行配置更新</span><br/> <span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">$this</span>->containerConfigUpdate($module);<br/> }<br/> }<br/></code>
Une copie du code précédent est jointe ici. Vous pouvez consulter le code pour voir le flux d'exécution, et chaque étape est brièvement expliquée.
L'avis personnel de Kaka optimise le code source
Kaka ne se sent pas très rigoureux dans l'étape de mise en place du module, car la méthode init sera réalisée en deux lieux mettre en œuvre.
La première fois que le module est vide, cela n'a aucun sens d'exécuter ce code.
Ce qui suit est un jugement lors de la mise à jour de la configuration de l'instance d'objet du conteneur pour déterminer si ce paramètre du module est vide. S'il n'est pas vide, il sera exécuté.
Pour la même raison, KaKa estime que la définition du chemin du module devrait également être incluse dans ce jugement.
Bien que la deuxième exécution écrasera le premier résultat, Kaka pense qu'il serait préférable de l'utiliser comme l'image ci-dessous.
Ceci est le contenu final de la section précédente Ainsi, lors de la mise à jour de la configuration de l'instance, il n'y a aucune explication sur ce qui est mis à jour et comment le mettre à jour.
Des explications seront faites dans cette section, qui peut également être lue avec la carte mentale en préface.
Dans cette section, la sensation de clic est la plus important Le contenu est tel qu'indiqué dans l'image ci-dessous.
On peut tracer une ou deux méthodes à volonté pour voir quelles méthodes y sont exécutées.
Méthode de suivi Db::init()
Après avoir suivi la méthode, vous pouvez voir qu'elle attribue la valeur à l'attribut config dans la classe Db et attribue le valeur dans la base de données Donnez l'attribut config dans la classe Db.
Méthode de suivi $this->middleware->setConfig()
Quand vous arrivez à la classe middleware, vous pouvez voir que cette classe la configuration est fusionnée avec la classe de paramètres transmise et la valeur de l'attribut config est également attribuée.
L'effet obtenu par la méthode init de la classe Db dans le cas ci-dessus est cohérent.
Ce que je tiens à mentionner ici, c'est que 对容器中的对象实例进行更新配置
Sur cette photo, vous pouvez voir que la partie violette n'est pas référencée dans cette classe.
Alors, comment cela peut-il être exécuté ! C'est parce que la classe App hérite de la classe conteneur. Il existe quatre méthodes magiques dans la classe conteneur, dont la méthode __get, qui est la méthode qui sera exécutée lors de l'obtention d'attributs inexistants.
Une méthode make est exécutée dans la méthode magique __get. Cette méthode make a été mentionnée à plusieurs reprises. Cette méthode renverra éventuellement une instance de l'application, puis utilisera cette instance pour appeler la méthode correspondante. classe d'instance.
Cela doit être bien compris. La lecture du code source est comme ça. Ce n'est qu'ainsi que nous pourrons améliorer nos capacités de programmation et de réflexion.
Cette section donnera une brève explication du mode de débogage et soulèvera brièvement la redondance du code-cadre.
Aucun code écrit par qui que ce soit n'est sans failles. S'il y en a, alors vous n'avez pas atteint un certain niveau de réussite.
Mode débogage
Seule la première moitié de la méthode d'initialisation est mentionnée dans la première section, car avant cette section, tout le discours portait sur le contenu d'initialisation de l'application.
Le contenu de cette section sera brièvement expliqué ensuite.
Le contenu suivant n'est probablement pas très facile à comprendre, car il n'est pas du tout utilisé au travail.
Il suffit de connaître les trois ci-dessus pour l'instant. J'écrirai un article expliqué plus tard.
À propos de la redondance du code-cadre
Cela ne représente que l'opinion personnelle de Kaka.
Vous pouvez d'abord jeter un œil à cette partie du code. Ces deux codes sont-ils très familiers Oui, vous l'avez vu dans la mise à jour de la configuration de l'instance d'objet conteneur dans la méthode init ci-dessus ?
Comme le montre l'image
Ceci est l'opinion personnelle de Kaka En raison de l'interprétation du code source de Kaka pour la 5.1, je ne sais pas si la nouvelle version a réussi. . changé.
Cette section traite principalement de l'application d'initialisation dans le processus d'exécution du framework.
En ce qui concerne les nombreux processus d'exécution sous la méthode run de la classe app, il n'y a pas beaucoup d'explications dans cette section.
En train de lire le code source, je vous ai donné un bon conseil, c'est-à-dire comment vérifier où une méthode est exécutée.
Cette méthode est debug_backtrace
. Cette méthode nécessite de l'utiliser plusieurs fois avant de savoir comment l'utiliser, car il y a aussi beaucoup d'informations inutiles dans les résultats imprimés.
Cette méthode est très efficace dans le processus de débogage du code source. Assurez-vous de faire bon usage de cette méthode.
Voici maintenant une introduction particulièrement détaillée à la méthode init d'initialisation de l'application.
Parmi eux, Kaka estime que la meilleure partie de cette conception est celle où l'instance d'objet dans le conteneur est mise à jour et configurée. Tout d'abord, toutes les configurations sont lues, puis la configuration est définie via les méthodes de chaque classe. .
Ce type d'idées de planification et de conception de code mérite d'être appris.
Enfin, nous avons parlé du problème de redondance du code du mode de débogage et du framework Concernant le mode de débogage, je voudrais rappeler à tous que le mode de débogage du projet en ligne doit être désactivé.
Sinon, votre projet sera comme courir nu sans aucune sécurité.
Ce qui est un peu difficile à comprendre, c'est la zone tampon. Kaka estime qu'il n'est pas nécessaire d'approfondir les détails de ce contenu pour le moment. Nous devrions d'abord le comprendre, puis mener des recherches approfondies. .
On estime que ce contenu dans la zone tampon est rarement utilisé par les personnes qui travaillent depuis trois ou quatre ans, alors apprenez d'abord à le connaître et sachez de quoi il s'agit. Après que Kaka l'ait appris plus tard, je l'ai appris plus tard. le complétera pour tout le monde.
Jusqu'à présent, l'application initiale du processus d'exécution du framework est terminée. Il n'y a pas grand chose à apprendre dans cette section, principalement les modèles de conception de code et les idées d'implémentation.
Pour cette dernière photo, vous devez suivre le code source et jeter un oeil !
«Continuez à apprendre, continuez à bloguer, continuez à partager, c'est la conviction à laquelle Kaka a toujours adhéré dans l'immense Internet, je suis Kaka, à bientôt dans le prochain numéro
.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!