YII(-) 소스코드 분석

WBOY
풀어 주다: 2016-08-08 09:33:00
원래의
1210명이 탐색했습니다.

첫 번째 소스 코드 분석으로 yii(Wai Ai Ai 대신 Wai Yiyi로 발음)를 선택했습니다. 칭찬에 대해서는 더 이상 언급하지 않고 바로 본론으로 들어가겠습니다. 먼저 자료를 준비하세요. 공식 홈페이지에서 최신 버전의 yii 소스코드 패키지(1.1.15)를 직접 다운로드하시는 것을 권장합니다.

데모에는 가장 간단한 애플리케이션 중 하나인 helloworld가 있습니다. 이 애플리케이션은 yii 프레임워크를 사용하여 "hello world"라는 문장을 출력합니다.

여기부터 시작해 프레임워크가 최소한의 프로세스를 실행하기 위해 거치는 구성요소를 분석하고, 실행 프로세스를 간략하게 분석하겠습니다.

단일 항목 문서부터 읽기 시작하세요. (소스코드는 일반적으로 호출 시점부터 분석됩니다)

Index.php->

// Yii 부트스트랩 파일 포함

//시작 파일 소개

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

yii.php ->

//YiiBase는 공통 프레임워크 기능을 제공하는 도우미 클래스입니다.

//YiiBase는 전체 프레임워크를 서비스하는 도우미 클래스입니다. 여기에는 많은 중요한 상수가 정의되어 있습니다

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

//자동 로딩 클래스 등록

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

//인터페이스 클래스 가져오기

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

//애플리케이션 시작

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

코드는 여기서 끝나는 것 같고 페이지의 내용도 표시되지만 프레임워크가 무엇을 하는지는 알 수 없습니다. 따라서 이 단계를 세분화하여 내부 세부 정보를 공개해야 합니다.

Yii::createWebApplication()->run()은 세 부분으로 나눌 수 있습니다

    으이
  1. createWebApplication
  2. 달려
Yii란 무엇인가요?

yii.php 클래스 Yii 확장 YiiBase에서 이 코드 줄을 찾을 수 있습니다

은 YiiBase의 상속 클래스임을 나타내며 작성자의 확장자는 공백으로 남겨두므로 Yii는 단지 YiiBase에 대한 참조일 뿐입니다. 따라서 정적 메소드인 createWebApplication도 YiiBase에 있어야 합니다.

YiiBase.php에서 다음 메소드를 쉽게 찾을 수 있습니다:

공용 정적 함수 createWebApplication($config=null)

{

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

}

createApplication 작업을 전달합니다.

공개 정적 함수 createApplication($class,$config=null)

{

새로운 $class($config) 반환;

}

종합하면 createWebApplication()은 새로운 CWebApplication($config)을 반환합니다.

이 CWebApplication 클래스는 어디에 있나요? 어떻게 도입됐나요?

많은 질문을 받고 YiiBase.php로 돌아왔습니다

여기에는 매우 긴 배열이 정의되어 있습니다.

'CWebApplication' => '/web/CWebApplication.php', 이것은 자동 로딩 클래스의 멤버입니다

자동 로딩을 구현하는 방법은 spl_autoload_register의 관련 문서를 볼 수 있지만 여기에는 관련 없는 세부 사항이 있습니다.

계속해서 CWebApplication에 대해 더 자세히 살펴보겠습니다. /web/CWebApplication.php 파일을 엽니다.

앞서 언급했듯이 return new CWebApplication($config); 내 경험에 따르면 new를 사용할 때 일반적으로 생성자가 있지만 해당 생성자를 찾지 못했습니다. 그래서 찾아보니 CWebApplication 클래스가 CApplication을 확장한다는 사실을 발견했습니다. 마치 미꾸라지를 찾는 것과 같아서 단서를 따라 조금씩 찾아야 했고 인내심을 가져야 했습니다.

CApplication에는 실제로 생성자가 있으며 코드는 다음과 같습니다.

<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>
로그인 후 복사

//위 내용은 초기화, 클래스 참조 설정, 별칭, 경로 등으로 간주할 수 있습니다.

$ this- & gt; preinit () // 당분간 사용하지 않으며 추후 확장에 맡길 것으로 추정됩니다

$this->initSystemHandlers();//오류 처리 설정

$this->registerCoreComponents();//핵심 컴포넌트 등록

$this->configure($config); //구성 파일을 통해 클래스의 속성을 확장하고 비어 있으면 아무것도 하지 않습니다

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

$this->preloadComponents();

$this->init();

}

$this 아래의 일부 메소드는 상위 클래스에서 올 수 있으므로 현재 클래스에서 찾을 수 없습니다. 그렇지 않은 경우 ctrl+f를 사용하여 검색하는 것입니다. 확인해보세요 :

추상 클래스 CApplication은 CModule을 확장합니다.

분명히 CModule에 들어가야 합니다. 여전히 원하는 방법을 찾을 수 없으면 이전 프로세스를 계속하세요.

추상 클래스 CModule은 CComponent를 확장합니다

CComponent 클래스까지

이곳이 현재 이들의 본거지라는 뜻이다. 코드의 주석에서도 확인할 수 있습니다.

CComponent는 모든 구성요소의 기본 클래스입니다

제 생각이 맞다는 뜻입니다. 네, 기본 클래스입니다.

코드를 통해 현재 애플리케이션에서 많은 매개변수가 비어 있기 때문에 많은 로직을 직접 건너뛰었음을 알 수 있습니다.

이것을 보면 $this의 내용은 대략적으로 알 수 있습니다. 다시 돌아보자

새 CWebApplication($config)->run() 반환;

이전의 레이어별 분석을 통해 이때의 실행 방식도 쉽게 찾아볼 수 있다. CApplication 바로 내부:

<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教程有兴趣的朋友有所帮助。

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿