Yii Frameworkのprocess flow分析(一)


この記事では、route、filter、controller、actionなど、yiiがWebリクエストをどのように処理するかについて説明します.彼はどのように彼らのそれぞれの順序を手配して、同時にどのようなイベント関数を予約して、開発者にもっと良い制御をさせます.本文は一定のプログラミング基礎とyiiに対して一定の熟知が必要で、進級型に属する.また、プログラムが膨大で複雑なため、どのプログラムがどのクラスにあるかを確認してください.
Ready! Start...
まずindex.phpに違いありません.彼はアプリケーション全体のエントリファイルとして、様々な変数を初期化する役割を果たしています.次にコードを見て、ここではすべてのコードが一般的であることを約束します.
 
 1 <?php
2
3 // change the following paths if necessary
4 $yii=dirname(__FILE__).'/../yiiframework/framework/yii.php';
5 $config=dirname(__FILE__).'/protected/config/main.php';
6
7 // remove the following lines when in production mode
8 defined('YII_DEBUG') or define('YII_DEBUG',true);
9 // specify how many levels of call stack should be shown in each log message
10 defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
11
12 require_once($yii);
13 Yii::createWebApplication($config)->run();
ここで唯一関心を持つのは、最後の一言です.この文が私たちのRequest Processを開始したので、CreateWebApplicationがどのような操作をしたかを見てみましょう.
 
 1 //    WebApplication
2 public static function createWebApplication($config=null)
3 {
4 return self::createApplication('CWebApplication',$config);
5 }
6
7 // CWebApplication
8 public static function createApplication($class,$config=null)
9 {
10 return new $class($config);
11 }
12
13 // CWebApplication
14 // CApplication , CApplication
15 // CApplicaiton
16 public function __construct($config=null)
17 {
18 Yii::setApplication($this);
19
20 // set basePath at early as possible to avoid trouble
21 if(is_string($config))
22 $config=require($config);
23 if(isset($config['basePath']))
24 {
25 $this->setBasePath($config['basePath']);
26 unset($config['basePath']);
27 }
28 else
29 $this->setBasePath('protected');
30 Yii::setPathOfAlias('application',$this->getBasePath());
31 Yii::setPathOfAlias('webroot',dirname($_SERVER['SCRIPT_FILENAME']));
32 Yii::setPathOfAlias('ext',$this->getBasePath().DIRECTORY_SEPARATOR.'extensions');
33
34 $this->preinit();
35
36 $this->initSystemHandlers();
37 $this->registerCoreComponents();
38
39 $this->configure($config);
40 $this->attachBehaviors($this->behaviors);
41 $this->preloadComponents();
42
43 $this->init();
44 }
コードの注釈をよく読んで、コードを分析すると、構造関数全体がmain.phpのconfigurationを利用してappインスタンス全体を変数初期化していることがわかります.それぞれ1、ベースアドレス25行または29行2、Aliasを設定しています.なぜnamespaceのフォーマットを使用して、ファイルがパスを見つけることができるのかを知っています.30-32行3、preinitこれは予約された関数で、自分で拡張したApplicationでoverrideこれをoverrideして、制御を助けることができます.4、initSystemHandlersこれはYiiのExceptionHandlerを初期化するためのもので、現在の前提はあなたが開いていることです.5、registerCoreComponents、名前の上でとても理解しやすくて、核心のコントロールを登録して、この中にいくつかロードしなければならないcomponentがあって、主な仕事はcomponentをAPP->_に預けることですcomponents(ここのアプリはApplicationインスタンスを表しています)では、保存するときはインスタンス化されたプロセスであることに注意してください.ここでは、よりよく理解するためにコードを切り取ります.ここではmain.phpの構成とは関係ありません.ここではロードする必要があるので、後でmain.phpの構成に基づいていくつかの設定を変更するプロセスがあります.
 1     public function setComponent($id,$component)
2 {
3 if($component===null)
4 unset($this->_components[$id]);
5 else
6 {
7 $this->_components[$id]=$component;
8 if(!$component->getIsInitialized())
9 $component->init();
10 }
11 }
上のコードは、コアコンポーネントを登録する最もコアな部分です.7-9行目に注意してください.このことから分かるようにcomponentsに格納されるのは、各componentのインスタンスです.上のコードはCModule.phpファイルにあります.CApplicationはCModuleから継承されているからです.ここでもう一つの変数に注意しなければならないのは_componentConfig、コード(CModule.phpから)を見てみましょう.次のコードは上の関数に呼び出されます.
 1     public function setComponents($components,$merge=true)
2 {
3 foreach($components as $id=>$component)
4 {
5 if($component instanceof IApplicationComponent)
6 $this->setComponent($id,$component);
7 else if(isset($this->_componentConfig[$id]) && $merge)
8 $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
9 else
10 $this->_componentConfig[$id]=$component;
11 }
12 }
6行目は、説明の方法を使用していますが、ここでは私たちのポイントではありません.7-10行目を繰り返しています.前の論理に基づいて、IApplicationComponent以外のインスタンスだけが格納できることを知っています.componentConfigでは、IApplicationComponentとは?“After the application completes configuration, it will invoke the {@link init()} method of every loaded application component.」に関連するドキュメントの注釈があります.彼はIApplicationComponentをこのように説明していますが、実はinitメソッドがあります.setComponentメソッドで使われているので、9行目を参照してください.典型的なこのようなComponentにはどんなものがありますか?CCache、CAssetManager、CClientScriptなど、個人的にはpreloadがデフォルトのものだと思います.また、CLoggerなどは違います.彼は保存されます.componentConfig中.6、main.phpの関連配列をこのアプリケーションの属性に変換するconfigure.後で使うときは、直接属性を使って、この配列を使っていません.しかし、彼のここの属性はcomponent、import、moduleなどの第1緯の配列キーを指し、request、urlManagerのようなものではないことに注意してください.ここでは詳しく言う必要がありますが、ここで使用しているので_set,__getは操作を簡素化するとともに,このメカニズムが不明であれば,他のyiiのコードを読むのに一定の障害に直面する.次にコードを見て、configureメソッドはCModule.phpで
 1     public function configure($config)
2 {
3 if(is_array($config))
4 {
5 foreach($config as $key=>$value)
6 $this->$key=$value;
7 }
8 }
9
10 //In the CModule
11 public function __get($name)
12 {
13 if($this->hasComponent($name))
14 return $this->getComponent($name);
15 else
16 return parent::__get($name);
17 }
18
19
20 //In the CComponent,__set ,
21 //CWebApplication,CApplication,CModule
22 public function __set($name,$value)
23 {
24 $setter='set'.$name;
25 if(method_exists($this,$setter))
26 return $this->$setter($value);
27 else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
28 {
29 // duplicating getEventHandlers() here for performance
30 $name=strtolower($name);
31 if(!isset($this->_e[$name]))
32 $this->_e[$name]=new CList;
33 return $this->_e[$name]->add($value);
34 }
35 else if(is_array($this->_m))
36 {
37 foreach($this->_m as $object)
38 {
39 if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name)))
40 return $object->$name=$value;
41 }
42 }
43 if(method_exists($this,'get'.$name))
44 throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
45 array('{class}'=>get_class($this), '{property}'=>$name)));
46 else
47 throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
48 array('{class}'=>get_class($this), '{property}'=>$name)));
49 }
実際には、多くのconfigureのプロパティは存在しません.つまり、アクセスできません.例えば$this->requestとか、このときは存在しないので読み出し時に__を呼び出すget,格納時に呼び出す_set.次に,これらの存在しない属性を読み出して格納する際にどのように処理されるかを見てみよう.先に読んでみてください.getメソッド、行13を見て、私たちは彼が存在するかどうかを判断することができます_componentと_componentConfigの2つの配列にあるかどうかは、ある場合はそのまま読み込まれます.ここでは、この2つの配列に存在するかどうかを限られた判断をします.ではではsetではどのように処理されていますか?前述したように、ここで$keyはmain.phpの配列の1次元のkeyです.ここでは$key="componnets"を例に説明し、6行目を実行すると__が呼び出されるsetメソッドは、24行でsetter関数として貼り付けられ、setComponentsメソッドと呼ばれています.このメソッドは存在するので、このメソッドを実行します.この方法のコードを見てみましょう
 1     public function setComponents($components,$merge=true)
2 {
3 foreach($components as $id=>$component)
4 {
5 if($component instanceof IApplicationComponent)
6 $this->setComponent($id,$component);
7 else if(isset($this->_componentConfig[$id]) && $merge)
8 $this->_componentConfig[$id]=CMap::mergeArray($this->_componentConfig[$id],$component);
9 else
10 $this->_componentConfig[$id]=$component;
11 }
12 }
ここで明らかなのは、main.phpのcomponentsの内容を保存することです.componentまたは_componentConfig中.これでconfigure全体のプロセスが完了しました.次に、$this->requestを例に、プログラムがどのように取得されたかを簡単に説明します.通常はこの属性は含まれていませんので、readであればアクセスします.get、からcomponentまたは_componentConfigで取り、writeであれば行きます_setはその中に該当する項目がない(対応するsetterがないと考えてもよい)ので書くことはできません.
7、attachBehaviorsはアプリケーションを登録したBehaviorがイベントの集合である.
8、preloadComponents、これは前のconfigureからmain.phpにインポートしたpreload設定のcomponentで、彼は前のcorecomponentと同じように、_componentsで、初期化が完了します.9、最後はinitで、このプロセスはCWebApplicationのinit()を実行します. 
 
1     protected function init()
2 {
3 parent::init();
4 // preload 'request' so that it has chance to respond to onBeginRequest event.
5 $this->getRequest();
6 }
このgetRequestメソッドはrequest Componentを返し、CApplication.phpの957行目で、デフォルトではCHttpRequestが使用されます.このrequestは_componentから出てきたのは、実はIApplicationComponentだからです.ちなみに、yiiでは書き換えが大量に使われていますset,__get関数なので、$this->$key=$valueが表示されますが、書き換えられた可能性があり、必ずしも属性ではなくsetterである可能性があります.手順6に従ってyiiのgetterアプリケーションとsetterアプリケーションをよく理解するが、対応するプロパティが存在しない場合にのみ呼び出されることに注意する必要がある.本題に戻ると、ここは比較的回り道で、私は関連するコードを貼って、コードを結合して見ると簡単です.
 
 1     //In the CWebApplication
2 protected function init()
3 {
4 parent::init();
5 // preload 'request' so that it has chance to respond to onBeginRequest event.
6 $this->getRequest();
7 }
8
9 //In the CApplicaiton
10 public function getRequest()
11 {
12 return $this->getComponent('request');
13 }
14
15
16 //In the CModule
17 public function getComponent($id,$createIfNull=true)
18 {
19 if(isset($this->_components[$id]))
20 return $this->_components[$id];
21 else if(isset($this->_componentConfig[$id]) && $createIfNull)
22 {
23 $config=$this->_componentConfig[$id];
24 if(!isset($config['enabled']) || $config['enabled'])
25 {
26 Yii::trace("Loading \"$id\" application component",'system.CModule');
27 unset($config['enabled']);
28 $component=Yii::createComponent($config);
29 $component->init();
30 return $this->_components[$id]=$component;
31 }
32 }
33 }
注記このセグメントコードが属するクラスを説明します.次のメソッドは上記のメソッドによって呼び出されます.getComponentメソッドを見てみましょう.注意20行です.ここでrequest componentに対応するインスタンスが得られます.ここで28行目といえば、これまでのステップでpreloadComponentsメソッドでmain.phpのconfigureを対応するcomponentをインスタンス化していたが、残りは非componentであり、ここでの28行は、中遅延ロード(初期化)と理解され、$configに基づいてcomponentインスタンスを作成し、_componentConfig中.
やっとアプリケーションのconstruct過程を説明しました.