Heim  >  Artikel  >  Backend-Entwicklung  >  Quellcode-Analyse von YII (-)

Quellcode-Analyse von YII (-)

WBOY
WBOYOriginal
2016-08-08 09:33:001203Durchsuche

Als meine erste Quellcode-Analyse habe ich yii (ausgesprochen Wai Yiyi statt Wai Ai Ai) gewählt; ich werde nicht mehr über sein Lob sagen und gleich zur Sache kommen. Bereiten Sie zunächst die Materialien vor. Es wird empfohlen, die neueste Version des yii-Quellcodepakets (1.1.15) direkt von der offiziellen Website herunterzuladen.

Es gibt eine der einfachsten Anwendungen in den Demos – helloworld. Sie verwendet das yii-Framework, um einen Satz auszugeben: „hello world“;

Ich werde damit beginnen, die Komponenten analysieren, die das Framework durchläuft, um einen Mindestprozess auszuführen, und kurz seinen laufenden Prozess analysieren.

Beginnen Sie mit dem Lesen des einzelnen Einreisedokuments. (Quellcode wird in der Regel ab dem Aufrufpunkt analysiert)

Index.php->

// Yii-Bootstrap-Datei einschließen

//Startdatei einführen

require_once(dirname(__FILE__).'/../../framework/yii.php');

yii.php ->

//YiiBase ist eine Hilfsklasse, die allgemeine Framework-Funktionen bereitstellt.

//YiiBase ist eine Hilfsklasse, die das gesamte Framework bedient. Hier werden viele wichtige Konstanten definiert

require(dirname(__FILE__).'/YiiBase.php');

//Automatische Ladeklasse registrieren

spl_autoload_register(array('YiiBase','autoload'));

//Schnittstellenklasse importieren

require(YII_PATH.'/base/interfaces.php');

//Starten Sie die Anwendung

Yii::createWebApplication()->run();

Der Code scheint hier zu enden und der Inhalt der Seite wird ebenfalls angezeigt, aber wir haben keine Ahnung, was das Framework macht. Deshalb müssen wir diesen Schritt aufschlüsseln und die darin enthaltenen Details offenlegen.

Yii::createWebApplication()->run() kann in drei Teile unterteilt werden

    Yii
  1. Webanwendung erstellen
  2. Laufen
Was ist Yii?

Diese Codezeile finden Sie in der yii.php-Klasse „Yii erweitert YiiBase“

gibt an, dass es sich um die geerbte Klasse von YiiBase handelt und die Erweiterung des Autors leer bleibt, sodass Yii nur ein Verweis auf YiiBase ist. Daher muss die statische Methode createWebApplication auch in YiiBase gefunden werden.

In YiiBase.php ist diese Methode leicht zu finden:

öffentliche statische Funktion createWebApplication($config=null)

{

return self::createApplication('CWebApplication',$config);

}

Es übergibt die Aufgabe an createApplication:

öffentliche statische Funktion createApplication($class,$config=null)

{

new $class($config); zurückgeben

}

Zusammengenommen ist createWebApplication () die Rückgabe einer neuen CWebApplication($config);

Wo ist diese CWebApplication-Klasse? Wie wurde es eingeführt?

Mit einer Reihe von Fragen kehrte ich zu YiiBase.php zurück

Dort ist ein sehr langes Array definiert, Sie finden:

'CWebApplication' => '/web/CWebApplication.php', dies ist ein Mitglied der Autoloading-Klasse

Wie das automatische Laden implementiert wird, können Sie in den relevanten Dokumenten von spl_autoload_register einsehen, aber hier ist ein irrelevantes Detail.

Lassen Sie uns weiter tiefer in CWebApplication eintauchen. Öffnen Sie die Datei /web/CWebApplication.php.

Wie bereits erwähnt, gibt es meiner Erfahrung nach einen Konstruktor, den ich jedoch nicht in der übergeordneten Klasse gefunden habe Also schaute ich nach und entdeckte, dass die Klasse CWebApplication CApplication erweitert. Es war, als würde ich nach einer Schmerle suchen, ich musste den Hinweisen folgen und sie Stück für Stück finden, und ich musste geduldig sein.

Es gibt tatsächlich einen Konstruktor in CApplication, der Code lautet wie folgt:

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> __construct(<span>$config</span>=<span>null</span><span>)

         {

                   Yii</span>::setApplication(<span>$this</span><span>);

 

                   </span><span>//</span><span> set basePath at early as possible to avoid trouble</span>

                   <span>if</span>(<span>is_string</span>(<span>$config</span><span>))

                            </span><span>$config</span>=<span>require</span>(<span>$config</span><span>);

                   </span><span>if</span>(<span>isset</span>(<span>$config</span>['basePath'<span>]))

                   {

                            </span><span>$this</span>->setBasePath(<span>$config</span>['basePath'<span>]);

                            </span><span>unset</span>(<span>$config</span>['basePath'<span>]);

                   }

                   </span><span>else</span>

                            <span>$this</span>->setBasePath('protected'<span>);

                   Yii</span>::setPathOfAlias('application',<span>$this</span>-><span>getBasePath());

                   Yii</span>::setPathOfAlias('webroot',<span>dirname</span>(<span>$_SERVER</span>['SCRIPT_FILENAME'<span>]));

                   </span><span>if</span>(<span>isset</span>(<span>$config</span>['extensionPath'<span>]))

                   {

                            </span><span>$this</span>->setExtensionPath(<span>$config</span>['extensionPath'<span>]);

                            </span><span>unset</span>(<span>$config</span>['extensionPath'<span>]);

                   }

                   </span><span>else</span><span>

                            Yii</span>::setPathOfAlias('ext',<span>$this</span>->getBasePath().DIRECTORY_SEPARATOR.'extensions'<span>);

                   </span><span>if</span>(<span>isset</span>(<span>$config</span>['aliases'<span>]))

                   {

                            </span><span>$this</span>->setAliases(<span>$config</span>['aliases'<span>]);

                            </span><span>unset</span>(<span>$config</span>['aliases'<span>]);

                   }</span></spanmicrosoft>

// Das Obige kann als Initialisierung, Festlegen von Klassenreferenzen, Aliasnamen, Pfaden usw. betrachtet werden.

$ preinit (); // Wird vorerst nicht verwendet, es wird geschätzt, dass es der späteren Erweiterung überlassen bleibt

$this->initSystemHandlers();//Fehlerbehandlung festlegen

$this->registerCoreComponents();//Kernkomponenten registrieren

$this->configure($config); //Erweitern Sie die Eigenschaften der Klasse über die Konfigurationsdatei und tun Sie nichts, wenn sie leer ist

$this->attachBehaviors($this->behaviors);

$this->preloadComponents();

$this->init();

}

Einige der Methoden unter $this können in der aktuellen Klasse nicht gefunden werden, da sie möglicherweise von der übergeordneten Klasse stammen. Wenn nicht, gehen Sie zur Deklaration der Klasse Überprüfen Sie:

abstrakte Klasse CApplication erweitert CModule

Natürlich müssen Sie CModule eingeben. Wenn Sie die gewünschte Methode immer noch nicht finden können, fahren Sie mit dem vorherigen Vorgang fort:

Abstrakte Klasse CModule erweitert CComponent

bis Klasse CComponent

Das bedeutet, dass dies die aktuelle Heimatbasis dieser Jungs ist. Sie können es auch an den Kommentaren im Code erkennen:

CComponent ist die Basisklasse für alle Komponenten

Das bedeutet, dass meine Idee richtig ist, ja, es ist die Basisklasse.

Durch den Code können wir feststellen, dass in unserer aktuellen Anwendung viel Logik direkt übersprungen wird, da viele Parameter leer sind.

Wenn man das sieht, ist der Inhalt von $this ungefähr klar. Schauen wir noch einmal zurück

neue CWebApplication($config)->run(); zurückgeben

Durch die vorherige schichtweise Analyse ist die Ausführungsmethode zu diesem Zeitpunkt auch leicht zu finden. Nur in CAnwendung:

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span><span> run()

         {

                   </span><span>if</span>(<span>$this</span>->hasEventHandler('onBeginRequest'<span>)){

                            </span><span>$this</span>->onBeginRequest(<span>new</span> CEvent(<span>$this</span><span>));

                   }

 

                   </span><span>register_shutdown_function</span>(<span>array</span>(<span>$this</span>,'end'),0,<span>false</span><span>);

                   </span><span>$this</span>-><span>processRequest();  

                   </span><span>if</span>(<span>$this</span>->hasEventHandler('onEndRequest'<span>)){

                            </span><span>$this</span>->onEndRequest(<span>new</span> CEvent(<span>$this</span><span>));

                   }

 

         }</span></spanmicrosoft>

 

重点放在:$this->processRequest(); 因为前面和后面部分都是注册事件相关的,当前条件下执行不到。

<spanmicrosoft yahei font-size:><span>abstract</span> <span>public</span> <span>function</span> processRequest(); 这个方法在当前类中是抽象的,所以肯定在它的子类中实现了。回去找CWebApplication:

         <span>public</span> <span>function</span><span> processRequest()

         {

                   </span><span>if</span>(<span>is_array</span>(<span>$this</span>->catchAllRequest) && <span>isset</span>(<span>$this</span>->catchAllRequest[0<span>]))

                   {

                            </span><span>$route</span>=<span>$this</span>->catchAllRequest[0<span>];

                            </span><span>foreach</span>(<span>array_splice</span>(<span>$this</span>->catchAllRequest,1) <span>as</span> <span>$name</span>=><span>$value</span><span>)

                                     </span><span>$_GET</span>[<span>$name</span>]=<span>$value</span><span>;

                   }

                   </span><span>else</span>

                            <span>$route</span>=<span>$this</span>->getUrlManager()->parseUrl(<span>$this</span>-><span>getRequest());

 

                   </span><span>$this</span>->runController(<span>$route</span><span>);

         }</span></spanmicrosoft>

 

 

注意重点在$this->runController($route);

 

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> runController(<span>$route</span><span>)

         {

                   </span><span>if</span>((<span>$ca</span>=<span>$this</span>->createController(<span>$route</span>))!==<span>null</span><span>)

                   {

                            </span><span>list</span>(<span>$controller</span>,<span>$actionID</span>)=<span>$ca</span><span>;

 

                            </span><span>$oldController</span>=<span>$this</span>-><span>_controller;

                            </span><span>$this</span>->_controller=<span>$controller</span><span>;

                            </span><span>$controller</span>-><span>init();

                            </span><span>$controller</span>->run(<span>$actionID</span><span>);

                            </span><span>$this</span>->_controller=<span>$oldController</span><span>;

                   }

                   </span><span>else</span>

                            <span>throw</span> <span>new</span> CHttpException(404,Yii::t('yii','Unable to resolve the request "{route}".',

                                     <span>array</span>('{route}'=><span>$route</span>===''?<span>$this</span>->defaultController:<span>$route</span><span>)));

         }</span></spanmicrosoft>

 

 

我们要注意的代码只有两行:

$controller->init();

$controller->run($actionID);

这里的$controller可以能过查看createController得知,就是默认的控制器Sitecontroller.php

而Action则是index,你问我是怎么看出来的?哈哈,我在猜不出来的地方echo或var_dump一下不就可以了吗?这么简单的逻辑,还轮不到xdebug 这样的神器出场。

显然,init什么也没有做,看看run做了什么

Sitecontroller中没有run方法,又要去它的父类中查找。

class SiteController extends CController

 

在CController中有这个方法:

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> run(<span>$actionID</span><span>)

         {

                   </span><span>if</span>((<span>$action</span>=<span>$this</span>->createAction(<span>$actionID</span>))!==<span>null</span><span>)

                   {

                            </span><span>if</span>((<span>$parent</span>=<span>$this</span>->getModule())===<span>null</span><span>){

                                     </span><span>$parent</span>=Yii::<span>app();

                            }

 

                            </span><span>if</span>(<span>$parent</span>->beforeControllerAction(<span>$this</span>,<span>$action</span><span>))

                            {

                                     </span><span>$this</span>->runActionWithFilters(<span>$action</span>,<span>$this</span>-><span>filters());

                                     </span><span>$parent</span>->afterControllerAction(<span>$this</span>,<span>$action</span><span>);

                            }

                   }

                   </span><span>else</span>

                            <span>$this</span>->missingAction(<span>$actionID</span><span>);

         }

 </span></spanmicrosoft>

 

能过查看$this->createAction($actionID),得到return new CInlineAction($this,$actionID);

我们呆会再看这个CInlineAction,先看$this->runActionWithFilters($action,$this->filters());

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> runActionWithFilters(<span>$action</span>,<span>$filters</span><span>)

         {

                   </span><span>if</span>(<span>empty</span>(<span>$filters</span><span>)){

                            </span><span>$this</span>->runAction(<span>$action</span><span>);

                   }

                   </span><span>else</span><span>

                   {

                            </span><span>$priorAction</span>=<span>$this</span>-><span>_action;

                            </span><span>$this</span>->_action=<span>$action</span><span>;

                            CFilterChain</span>::create(<span>$this</span>,<span>$action</span>,<span>$filters</span>)-><span>run();

                            </span><span>$this</span>->_action=<span>$priorAction</span><span>;

                   }

         }</span></spanmicrosoft>

 

显然$filters是空的,所以执行第一个表达式$this->runAction($action);

 

<spanmicrosoft yahei font-size:><span>public</span> <span>function</span> runAction(<span>$action</span><span>)

         {

 

                   </span><span>$priorAction</span>=<span>$this</span>-><span>_action;

                   </span><span>$this</span>->_action=<span>$action</span><span>;

                   </span><span>if</span>(<span>$this</span>->beforeAction(<span>$action</span><span>))

                   {

 

                            </span><span>if</span>(<span>$action</span>->runWithParams(<span>$this</span>->getActionParams())===<span>false</span><span>){

                                     </span><span>$this</span>->invalidActionParams(<span>$action</span><span>);

                            }

 

                            </span><span>else</span><span>{

                                     </span><span>$this</span>->afterAction(<span>$action</span><span>);

 

                            }

 

                   }

                   </span><span>$this</span>->_action=<span>$priorAction</span><span>;

         }</span></spanmicrosoft>

 

 

这段代码的重点是 $action->runWithParams($this->getActionParams())这一句;

这里的$action就是$this->createAction($actionID)返回的结果,而它的结果就是

return new CInlineAction($this,$actionID);

 

CInlineAction.php

是时候查看CInlineAction了;

 

        

<spanmicrosoft yahei font-size:> <span>public</span> <span>function</span> runWithParams(<span>$params</span><span>)

         {

                   </span><span>$methodName</span>='action'.<span>$this</span>-><span>getId();

                   </span><span>$controller</span>=<span>$this</span>-><span>getController();

                   </span><span>$method</span>=<span>new</span> ReflectionMethod(<span>$controller</span>, <span>$methodName</span><span>);

                   </span><span>if</span>(<span>$method</span>->getNumberOfParameters()>0<span>)

                            </span><span>return</span> <span>$this</span>->runWithParamsInternal(<span>$controller</span>, <span>$method</span>, <span>$params</span><span>);

                   </span><span>else</span>

                            <span>return</span> <span>$controller</span>-><span>$methodName</span><span>();

         }</span></spanmicrosoft>

 

哇哦,好高级,居然还用了反射,不过我喜欢!

不过呢,打印$method发现:

object(ReflectionMethod)#6 (2) {

 

["name"]=>

 

string(11) "actionIndex"

 

["class"]=>

 

string(14) "SiteController"

 

}

没有参数,所以此处代码相当于是执行了SiteController->actionIndex();

在class SiteController extends CController中可以看到actionIndex 的定义

        

<spanmicrosoft yahei font-size:> <span>public</span> <span>function</span><span> actionIndex()

         {

                   </span><span>echo</span> 'Hello World'<span>;

         }</span></spanmicrosoft>

 

于是就看到屏幕上那一句Hello World ,整个程序也就跑完了。也许有人要问了,为什么输出一句话还这么复杂,不是脱了裤子打屁吗? (请允许我的粗俗);

如果是这么简单的需求,当然不可能这么干。举这个例子,只是说明yii的基础流程,为下面的复杂应用做一个过渡。

Yii作为一个优秀的oop框架,这个例子只是介绍了它的继承,接口,mvc中的vc特性,关于数据模型,我将在后面的分析中陆续给出。最终的目标,是利用yii框架简化我们的开发过程。

好了,今天的分析就在到了,如果有什么不妥的,请留言,如果觉得有帮助,请顺手点个推荐!

以上就介绍了YII 的源码分析(-),包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:Centos-Yum-Lamp-UmgebungNächster Artikel:Centos-Yum-Lamp-Umgebung