Heim > php教程 > PHP开发 > Hauptteil

Yii Framework-Analyse (4) – Detaillierte Analyse der Ausführungsfunktion von WebApplication

黄舟
Freigeben: 2016-12-27 11:15:44
Original
1393 Leute haben es durchsucht

Der letzte Satz des Eingabeskripts der Yii-Anwendung startet WebApplication

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

CApplication:

public function run()
{
    $this->onBeginRequest(new CEvent($this));
    $this->processRequest();
    $this->onEndRequest(new CEvent($this));
}
Nach dem Login kopieren

processRequest() beginnt mit der Verarbeitung der Anfrage, implementiert durch CWebApplication:

public function processRequest()
{
    if(is_array($this->catchAllRequest) && isset($this->catchAllRequest[0]))
    {
        $route=$this->catchAllRequest[0];
        foreach(array_splice($this->catchAllRequest,1) as $name=>$value)
            $_GET[$name]=$value;
    }
    else
        $route=$this->getUrlManager()->parseUrl($this->getRequest());
    $this->runController($route);
}
Nach dem Login kopieren

parseUrl() der urlManager-Anwendungskomponente erstellt $route (eine Zeichenfolge in der Form von ControllerID/ActionID) und runController( ) beginnt mit der Erstellung des Controller-Objekts „HTTP-Anfragen verarbeiten“.

Der Wert von $route kann die folgenden Situationen haben:
- leer: ersetzt durch defaultController-Wert
- „moduleID/controllerID/actionID“:
- „controllerID“ unter Modul /; actionID“: Die häufigste Form
- „folder1/folder2/controllerID/actionID“ Controller in mehrstufigen Verzeichnissen

runController ruft zuerst createController() auf, um ein Controller-Objekt zu erstellen

public function createController($route,$owner=null)
{
    // $owner为空则设置为$this,即 $_app对象
    if($owner===null)
        $owner=$this;
    // $route为空设置为defaultController,在$config里配置
    if(($route=trim($route,’/'))===”)
        $route=$owner->defaultController;
    $caseSensitive=$this->getUrlManager()->caseSensitive;
 
    $route.=’/';
    // 逐一取出 $route 按 ‘/’分割后的第一段进行处理
    while(($pos=strpos($route,’/'))!==false)
    {
        // $id 里存放的是 $route 第一个 ‘/’前的部分
        $id=substr($route,0,$pos);
        if(!preg_match(‘/^\w+$/’,$id))
            return null;
        if(!$caseSensitive)
            $id=strtolower($id);
        // $route 存放’/’后面部分
        $route=(string)substr($route,$pos+1);
        if(!isset($basePath)) // 完整$route的第一段
        {
            // 如果$id在controllerMap[]里做了映射
            // 直接根据$id创建controller对象
            if(isset($owner->controllerMap[$id]))
            {
                return array(
                    Yii::createComponent($owner->controllerMap[$id],$id,$owner===$this?null:$owner),
                    $this->parseActionParams($route),
                );
            }
 
            // $id 是系统已定义的 module,根据$id取得module对象作为$owner参数来createController
            if(($module=$owner->getModule($id))!==null)
                return $this->createController($route,$module);
            // 控制器所在的目录
            $basePath=$owner->getControllerPath();
            $controllerID=”;
        }
        else
            $controllerID.=’/';
        $className=ucfirst($id).’Controller’;
        $classFile=$basePath.DIRECTORY_SEPARATOR.$className.’.php’;
        // 控制器类文件存在,则require并创建控制器对象&返回
        if(is_file($classFile))
        {
            if(!class_exists($className,false))
            require($classFile);
            if(class_exists($className,false) && is_subclass_of($className,’CController’))
            {
                $id[0]=strtolower($id[0]);
                return array(
                    new $className($controllerID.$id,$owner===$this?null:$owner),
                    $this->parseActionParams($route),
                );
            }
            return null;
        }
        // 未找到控制器类文件,可能是多级目录,继续往子目录搜索
        $controllerID.=$id;
        $basePath.=DIRECTORY_SEPARATOR.$id;
    }
}
Nach dem Login kopieren

createController() gibt ein erstelltes Controller-Objekt und eine ActionID zurück, runController() ruft die init()-Methode des Controllers auf und run($actionID), um den Controller auszuführen:

public function runController($route)
{
    if(($ca=$this->createController($route))!==null)
    {
        list($controller,$actionID)=$ca;
        $oldController=$this->_controller;
        $this->_controller=$controller;
        $controller->init();
        $controller->run($actionID);
        $this->_controller=$oldController;
    }
    else
        throw new CHttpException( 404, Yii::t(‘yii’,'Unable to resolve the request “{route}”.’, array( ‘{route}’=>$route===” ? $this->defaultController:$route)));
    }
Nach dem Login kopieren

$controller ->Es gibt Keine Aktion in init(), run():

public function run($actionID)
{
    if(($action=$this->createAction($actionID))!==null)
    {
       if(($parent=$this->getModule())===null)
           $parent=Yii::app();
       if($parent->beforeControllerAction($this,$action))
       {
           $this->runActionWithFilters($action,$this->filters());
           $parent->afterControllerAction($this,$action);
       }
    }
    else
        $this->missingAction($actionID);
}
Nach dem Login kopieren

$controller->Action-Objekt wird zuerst in run($actionID) erstellt:

public function createAction($actionID)
{
    // 为空设置为defaultAction
    if($actionID===”)
        $actionID=$this->defaultAction;
    // 控制器里存在 ‘action’.$actionID 的方法,创建CInlineAction对象
    if(method_exists($this,’action’.$actionID) && strcasecmp($actionID,’s')) // we have actions method
        return new CInlineAction($this,$actionID);
    // 否则根据actions映射来创建Action对象
    else
        return $this->createActionFromMap($this->actions(),$actionID,$actionID);
}
Nach dem Login kopieren

hier Es kann sein Es ist ersichtlich, dass der Controller die Aktionsmethode nicht direkt aufruft, sondern ein Aktionsobjekt benötigt, um die Controller-Aktion auszuführen. Dies vereinheitlicht die Verarbeitung von Aktionen durch das durch die Controller-Methode und Aktionen abgebildete Aktionsobjekt, dh zwei Formen der Aktionsverarbeitung. Sie sind alle im run()-Aufruf der IAction-Schnittstelle vereint.

Die IAction-Schnittstelle erfordert die Implementierung von drei Methoden: run(), getId() und getController(). Die von Yii bereitgestellte CAction-Klasse erfordert, dass der Konstruktor den Controller und die Id bereitstellt und die Verarbeitung von getId implementiert () und getController (). Die Action-Klasse kann von CAction erben.

CInlineAction unter web/action, run() ist ein sehr einfacher Prozess, der die Aktionsmethode des Controllers aufruft:

class CInlineAction extends CAction
{
    public function run()
    {
        $method=’action’.$this->getId();
        $this->getController()->$method();
    }
}
Nach dem Login kopieren

Return to $controller->run($actionID )

public function run($actionID)
{
    if(($action=$this->createAction($actionID))!==null)
    {
        if(($parent=$this->getModule())===null)
            $parent=Yii::app();
        if($parent->beforeControllerAction($this,$action))
        {
            $this->runActionWithFilters($action,$this->filters());
            $parent->afterControllerAction($this,$action);
        }
    }
    else
        $this->missingAction($actionID);
}
Nach dem Login kopieren

Yii::app()->beforeControllerAction() gibt tatsächlich true zurück, sodass das Aktionsobjekt tatsächlich durch runActionWithFilters() des Controllers ausgeführt wird

public function runActionWithFilters($action,$filters)
{
    // 控制器里没有设置过滤器
    if(empty($filters))
        $this->runAction($action);
    else
    {
        // 创建过滤器链对象并运行
        $priorAction=$this->_action;
        $this->_action=$action;
        CFilterChain::create($this,$action,$filters)->run();
        $this->_action=$priorAction;
    }
}
Nach dem Login kopieren

Es gibt keinen Filter, runAction() ist die run()-Methode, die letztendlich das zuvor erstellte Aktionsobjekt aufruft:

public function runAction($action)
{
    $priorAction=$this->_action;
    $this->_action=$action;
    if($this->beforeAction($action))
    {
        $action->run();
        $this->afterAction($action);
    }
    $this->_action=$priorAction;
}
Nach dem Login kopieren

Jeder Filter muss die IFilter-Schnittstelle und die vom Filter implementierte preFilter()-Methode implementieren. Wird vor $action aufgerufen. >run(), wenn beurteilt wird, dass die Aktion ausgeführt werden kann, wird true zurückgegeben, andernfalls wird false zurückgegeben

if($filter1->preFilter())
if($filter2- > ;preFilter())
if($filtern->preFilter())
$action->run()
$filtern->postFilter()
$filter2-> postFilter ()
$filter1->postFilter()

Die häufigste Operation in Aktion ist das Rendern der Ansichtsdatei: renderPartial() und render(). render() fügt das Ergebnis nach der Verarbeitung der Ansichtsdatei in die Layoutdatei ein.

public function renderPartial($view,$data=null,$return=false,$processOutput=false)
{
    if(($viewFile=$this->getViewFile($view))!==false)
    {
        $output=$this->renderFile($viewFile,$data,true);
        if($processOutput)
            $output=$this->processOutput($output);
        if($return)
            return $output;
        else
            echo $output;
    }
    else
        throw new CException(Yii::t(‘yii’,'{controller} cannot find the requested view “{view}”.’,
            array(‘{controller}’=>get_class($this), ‘{view}’=>$view)));
}
Nach dem Login kopieren

getViewFile($view) ruft den vollständigen Pfad von $view ab:
$view beginnt mit „/“, verwendet das Systemansichtsverzeichnis als Startverzeichnis +$view+.php
$ Wenn die Ansicht einen Alias ​​enthält, suchen Sie nach dem tatsächlichen Pfad des Alias.
Andere verwenden das Modellansichtsverzeichnis als Startverzeichnis + $view+.php

Wenn der Renderer eines Drittanbieters nicht konfiguriert ist $config, in renderFile() Eigentlich wird das von Yii selbst bereitgestellte renderInternal() aufgerufen, um die Ansichtsdatei zu rendern:

public function renderFile($viewFile,$data=null,$return=false)
{
    $widgetCount=count($this->_widgetStack);
    // 如果配置了其他的ViewRenderer
    if(($renderer=Yii::app()->getViewRenderer())!==null)
        $content=$renderer->renderFile($this,$viewFile,$data,$return);
    else
        // yii 自身的render
        $content=$this->renderInternal($viewFile,$data,$return);
    if(count($this->_widgetStack)===$widgetCount)
        return $content;
    else
    {
        $widget=end($this->_widgetStack);
        throw new CException(Yii::t(‘yii’,'{controller} contains improperly nested widget tags in its view “{view}”. A {widget} widget does not have an endWidget() call.’,array(‘{controller}’=>get_class($this), ‘{view}’=>$viewFile, ‘{widget}’=>get_class($widget))));
    }
}
Nach dem Login kopieren

Yiis Renderer verwendet PHP selbst als Vorlagensystem:

public function renderInternal($_viewFile_,$_data_=null,$_return_=false)
{
    // extract函数将$_data_从数组中将变量导入到当前的符号表
    if(is_array($_data_))
        extract($_data_,EXTR_PREFIX_SAME,’data’);
    else
        $data=$_data_;
    if($_return_)
    {
        ob_start();
        ob_implicit_flush(false);
        require($_viewFile_);
        return ob_get_clean();
    }
    else
        require($_viewFile_);
}
Nach dem Login kopieren

render() Tatsächlich wird zuerst die Teilansichtsdatei gerendert, dann wird die renderFile-Layoutdatei gerendert und das Ergebnis der Ansichtsdatei wird als $content-Variable übergeben.

public function render($view,$data=null,$return=false)
{
    $output=$this->renderPartial($view,$data,true);
    if(($layoutFile=$this->getLayoutFile($this->layout))!==false)
        $output=$this->renderFile($layoutFile,array(‘content’=>$output),true);
 
    $output=$this->processOutput($output);
 
    if($return)
        return $output;
    else
        echo $output;
}
Nach dem Login kopieren

processOutput verarbeitet die Renderergebnisse, z. B. das Hinzufügen von CSS- oder JS-Skripten zum Kopf.

public function processOutput ($output)
{
    Yii::app()->getClientScript()->render($output);
 
    // if using page caching, we should delay dynamic output replacement
    if($this->_dynamicOutput!==null && $this->isCachingStackEmpty())
        $output=$this->processDynamicOutput($output);
 
    if($this->_pageStates===null)
        $this->_pageStates=$this->loadPageStates();
    if(!empty($this->_pageStates))
        $this->savePageStates($this->_pageStates,$output);
 
    return $output;
}
Nach dem Login kopieren

Das Obige ist die Yii-Framework-Analyse (4) – die detaillierte Analyse der Ausführungsfunktion von WebApplication. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn). !


Quelle:php.cn
Erklärung dieser Website
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
Beliebte Empfehlungen
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage