Heim >PHP-Framework >Denken Sie an PHP >Ausführungsprozess des ThinkPHP-Frameworks (mit Brainmap)
"Dieser Artikel stellt hauptsächlich den Ausführungsprozess des Frameworks vor
"
Wenn Sie nicht wissen, wie das Framework ausgeführt wird, ist der größte Teil des Codes einfach Durch das Lesen des Quellcodes lernen Sie die Designideen und Codemuster seines Frameworks kennen.
Der Ausführungsprozess besteht darin, die Dinge, die wir lernen, miteinander zu verbinden, um sie besser zu verstehen. Kaka zeichnet für Sie auch den Ausführungsprozess in Form einer Mindmap auf.
Solange jeder aus diesem Artikel ein wenig Wissen lernt, wird Kaka zufrieden sein.
Dieses Flussdiagramm dient nur dem Ausführungsprozess der Initialisierung. Der Rest des Ausführungsprozesses wird später ergänzt und allen in Form von Mindmaps präsentiert.
Der Inhalt hier wiederholt sich etwas mit dem Inhalt des Containers, da der Ausführungsprozess beginnt aus der Eintragsdatei und schließlich über den Container ausgeführt.
Dann geben Sie die Datei ein
来到initialize这个方法,先看上半部分。
microtime(true);
返回的是unix的微秒数memory_get_usage
返回的是分配给PHP的内存量,单位为字节static::setInstance($this);
这里是将app这个实例设置为容器实例$this->instance('app', $this);
这个在之前容器章节就提到了,就是为了把app这个类绑定到容器里边去,也就是注册树模式。这里有一个小的问题点给大家提出来,在初始化应用的这个方法里边存在这样一行代码。
有没有小伙伴对这个$this->env
和下边的$this->config
microtime(true);
gibt die Anzahl der Mikrosekunden in Unix zurückmemory_get_usage
gibt die Menge des PHP zugewiesenen Speichers in Bytes zurückstatic::setInstance($this);
Hier wird die App-Instanz festgelegt als eine Containerinstanz$this-> ; config
Es bestehen Zweifel an diesen beiden Aufrufen. 🎜Wenn Sie irgendwelche Zweifel haben, folgen Sie einfach Kaka und lesen Sie es. Wenn Sie keine Zweifel haben, können Sie weiterlesen.
Die App-Klasse ist eine geerbte Containerklasse, daher verfügen env und config weder in der App noch in der Containerklasse über diese beiden Attribute.
Wie kann man es dann direkt aufrufen! Und die Codeverfolgung wird auf die Env-Klasse und die Containerklasse zurückgeführt.
Um die Quelle zu kennen, müssen wir einen groben Blick auf den Code der Containerklasse werfen.
Nach einigem gründlichen Lesen können Sie im Bild unten einige Codezeilen sehen. Diese Codezeilen verwenden alle magische Methoden.
Wenn die env-Klasse, auf die zugegriffen wird, nicht existiert, wird die make-Methode ausgeführt.
Die Make-Methode ist im Containerkapitel so detailliert, dass sie nicht im Detail erklärt werden kann.
Diese Make-Methode gibt schließlich eine Instanz der Klasse zurück und speichert sie im Container.
Fügen Sie hier nur den Code einer Make-Methode ein. Wenn Sie nicht wissen, wie es geht, können Sie den vorherigen Artikel lesen.
Der letzte Schritt besteht darin, eine Reihe von Daten zu laden. Einzelheiten zum Laden finden Sie in der Mindmap im Vorwort.
Beim Lesen des Quellcodes tritt ein Problem auf, das schwer zu kontrollieren ist , eine Methode wird an verschiedenen Stellen ausgeführt Der Aufruf wurde an einigen Stellen durchgeführt, aber wir wissen eine Zeit lang wirklich nicht, wo sie aufgerufen wurde.
Hier ist eine Demonstration mit der Init-Methode.
Die init-Methode ist eine Methode zum Initialisieren einer Anwendung oder eines Moduls, aber der Modulparameter hat hier einen Nullwert.
Erstellen Sie zunächst einen Haltepunkt, um die relevanten Dateninformationen zu überprüfen.
Das gedruckte Ergebnis ist leer. Dies ist ein Fehler, den einige neue Lernpartner machen werden, da diese Methode nicht nur einmal aufgerufen werden kann.
Wenn alle Initialisierungsmodule leer sind, ist die Existenz dieser Methode nicht erforderlich.
Dann sollte die richtige Haltepunktmethode so aussehen.
Zu diesem Zeitpunkt wird es ein Problem geben. Diese Init-Methode wird offensichtlich zweimal aufgerufen. Wo ist also der andere Aufruf?
Wenn Sie die neue Technik nicht kennen, drucken Sie eine Reihe von Haltepunkten, um zu sehen, wo die Ausführung ausgeführt wird, z. B. das Drucken auf der oberen Ebene der Init.
Das heißt, das Drucken von Haltepunkten in der Initialisierungsmethode ist jedoch sehr mühsam und verschwendet wahrscheinlich viel Zeit und findet immer noch nicht die richtige Stelle.
Tipps: debug_backtrace()
Diese Methode generiert einen Backtrace, der alle Aufruforte einer Methode anzeigt.
Die Verwendung ist wie unten gezeigt. Sie müssen nur die Methode debug_backtrace ausdrucken.
Anhand der gewonnenen Dateninformationen kann die Positionierung sehr schnell durchgeführt werden.
Das erste Mal ist in Zeile 215 der App-Klasse.
Das zweite Mal erfolgt in 60 Zeilen thinkphp/library/think/route/dispatch/Module.php
classthinkphp/library/think/route/dispatch/Module.php
类的60行
可以在这里做一个打印,看一下这个module是否为index
所以说有了这个方法就可以非常快速地定位调用位置。
上文给大家提供了一个小技巧debug_backtrace
Wenn Sie den Ort zum zweiten Mal anrufen
🎜🎜können Sie hier einen Ausdruck machen, um zu sehen, ob es sich bei diesem Modul um einen Index handelt🎜🎜 Mit dieser Methode kann die Ortung also sehr schnell erfolgen der anrufende Ort. 🎜debug_backtrace
zeigt tatsächlich, wie man überprüft, wo eine Methode ausgeführt wird. 🎜🎜Und der Fall verwendet auch die Init-Methode zur Demonstration, denn der nächste Schritt besteht darin, ein tiefgreifendes Verständnis der Init-Methode zu erlangen. 🎜🎜Die wichtigsten Dinge, die in der Init-Methode erledigt werden, sind in der Mindmap oben klar beschrieben. 🎜bindTo
-Methode zur Bindungsregistrierung. bindTo
方法进行绑定注册的。env
env
In der Umgebungsvariablenkonfiguration besteht der letzte Schritt darin, die Objektinstanzen im Container zu konfigurieren und zu aktualisieren. Die spezifischen Aktualisierungen werden später ausführlich erläutert.
<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>Eine Kopie des vorherigen Codes ist hier beigefügt. Sie können sich den Code ansehen, um den Ausführungsprozess zu sehen, und jeder Schritt wird kurz erklärt.
Kakas persönliche Meinung zur Optimierung des Quellcodes
Kaka fühlt sich beim Einrichten des Moduls nicht sehr streng, da die Init-Methode an zwei Stellen ausgeführt wird. Wenn das Modul zum ersten Mal leer ist, macht es keinen Sinn, diesen Code auszuführen. Das Folgende ist eine Beurteilung beim Aktualisieren der Konfiguration der Objektinstanz des Containers, um festzustellen, ob der Parameter des Moduls leer ist. Wenn er nicht leer ist, wird er ausgeführt. Dann ist Kaka aus dem gleichen Grund der Meinung, dass auch die Festlegung des Modulpfads in dieses Urteil einbezogen werden sollte. 🎜🎜Obwohl die zweite Ausführung das erste Ergebnis überschreibt, ist Kaka der Meinung, dass es besser wäre, es wie im Bild unten zu verwenden. 🎜Im vorherigen Abschnitt finden Sie hier den endgültigen Inhalt Bei der Aktualisierung der Konfiguration gibt es keine Erklärung, was genau aktualisiert wird und wie es aktualisiert wird.
In diesem Abschnitt werden Erläuterungen gegeben, die auch mit der Mindmap im Vorwort gelesen werden können.
In diesem Abschnitt ist meiner Meinung nach der Inhalt im Bild unten am wichtigsten.
Wir können eine oder zwei Methoden nach Belieben verfolgen, um zu sehen, welche Methoden dort ausgeführt werden.
Tracking-Methode Db::init()
Nachdem Sie die Methode verfolgt haben, können Sie sehen, dass sie dem Konfigurationsattribut in der Db-Klasse einen Wert zuweist und den Wert in der Datenbank dem Konfigurationsattribut in der Db zuweist Klasse.
Tracking-Methode $this->middleware->setConfig()
Wenn Sie zur Middleware-Klasse kommen, können Sie sehen, dass die Konfiguration dieser Klasse und der übergebenen Parameterklasse zusammengeführt werden, und die Zuweisung erfolgt ebenfalls des config-Attributs.
Der im obigen Fall durch die Init-Methode der Db-Klasse erzielte Effekt ist konsistent.
Was ich hier erwähnen möchte, ist, dass Sie in 对容器中的对象实例进行更新配置
diesem Bild sehen können, dass der violette Teil in dieser Kategorie nicht erwähnt wird.
Wie kann das also umgesetzt werden? Dies liegt daran, dass die App-Klasse die Containerklasse erbt. Es gibt vier magische Methoden in der Containerklasse, von denen eine die __get-Methode ist, die beim Abrufen nicht vorhandener Attribute ausgeführt wird.
Eine Make-Methode wird in der magischen Methode __get ausgeführt. Diese Make-Methode wird schließlich eine Instanz der Anwendung zurückgeben und diese Instanz dann verwenden, um die Methode der entsprechenden Instanzklasse aufzurufen.
Das muss gut verstanden werden. Das Lesen des Quellcodes ist so. Nur so können wir unsere Programmierfähigkeiten und unser Denken verbessern.
Dieser Abschnitt enthält eine kurze Erläuterung des Debugging-Modus und des Framework-Codes. Redundante Situationen werden kurz angehoben.
Der von niemandem geschriebene Code ist ohne Lücken. Wenn es Lücken gibt, haben Sie ein bestimmtes Niveau nicht erreicht.
Debug-Modus
Im ersten Abschnitt wurde nur die erste Hälfte der Initialisierungsmethode erwähnt, da sich vor diesem Abschnitt alles um die Anwendungsinitialisierung init drehte.
Der Inhalt dieses Abschnitts wird im Folgenden kurz erläutert.
Es reicht vorerst, die oben genannten drei kennenzulernen. Wenn möglich, werde ich später einen Artikel schreiben, um sie zu erklären.
Über Framework-Code-Redundanz
Dies gibt nur Kakas persönliche Meinung wieder.
Sie können sich diesen Teil des Codes zuerst ansehen. Sind diese beiden Codes sehr vertraut? Ja, Sie haben ihn in der Aktualisierung der Containerobjektinstanz in der obigen Init-Methode gesehen.
Wie im Bild gezeigt
Dies ist Kakas persönliche Meinung. Aufgrund von Kakas Quellcode-Interpretation für 5.1 weiß ich nicht, ob die Änderungen in der neuen Version vorgenommen wurden.
In diesem Abschnitt wird hauptsächlich kurz die Initialisierungsanwendung im Framework-Ausführungsprozess erläutert.
Zu den vielen Ausführungsprozessen unter der Ausführungsmethode der App-Klasse gibt es in diesem Abschnitt nicht viele Erklärungen.
Beim Lesen des Quellcodes habe ich Ihnen einen guten Tipp gegeben, nämlich wie Sie überprüfen können, wo eine Methode ausgeführt wird.
Diese Methode ist debug_backtrace
. Bei dieser Methode müssen Sie sie einige Male anwenden, bevor Sie wissen, wie man sie verwendet, da die gedruckten Ergebnisse auch viele nutzlose Informationen enthalten.
Diese Methode ist beim Debuggen von Quellcode sehr effektiv. Nutzen Sie diese Methode unbedingt.
Die Init-Methode zum Initialisieren der Anwendung wird ausführlich vorgestellt.
Unter anderem ist Kaka der Meinung, dass der beste Teil dieses Entwurfs darin besteht, die Objektinstanz im Container zu aktualisieren und zu konfigurieren. Lesen Sie zunächst alle Konfigurationen und legen Sie die Konfiguration dann über die Methoden jeder Klasse fest.
Es lohnt sich, diese Art von Codeplanungs- und Designideen zu lernen.
Abschließend haben wir über das Code-Redundanzproblem des Debugging-Modus und des Frameworks gesprochen. In Bezug auf den Debugging-Modus möchte ich alle daran erinnern, dass der Debugging-Modus des Projekts online deaktiviert werden muss.
Sonst gleicht Ihr Projekt einem Streben ohne jegliche Sicherheit.
Was den Inhalt dieses Bereichs etwas schwer zu verstehen ist, ist Kaka der Ansicht, dass es vorerst nicht nötig ist, auf die Details einzugehen. Wir sollten ihn zunächst verstehen und dann eine eingehende Recherche durchführen .
Es wird geschätzt, dass dieser Teil des Puffers von Leuten, die seit drei oder vier Jahren arbeiten, selten verwendet wird. Lernen Sie ihn also zuerst kennen und wissen Sie, worum es später geht. Nachdem Kaka ihn gelernt hat, wird er ihn für alle ergänzen .
Dies ist das Ende der ersten Anwendung des Ausführungsprozesses des Frameworks. In diesem Abschnitt gibt es nichts zu tiefgründiges zu lernen, hauptsächlich die Codeentwurfsmuster und Implementierungsideen.
Für dieses letzte Bild müssen Sie dem Quellcode folgen und einen Blick darauf werfen!
“Beharrlichkeit beim Lernen, Beharrlichkeit beim Bloggen und Beharrlichkeit beim Teilen sind die Überzeugungen, an denen Kaka seit Beginn seiner Karriere immer festgehalten hat Das riesige Internet kann Ihnen helfen. Ich bin Kaka. Bis zum nächsten Mal.
Das obige ist der detaillierte Inhalt vonAusführungsprozess des ThinkPHP-Frameworks (mit Brainmap). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!