Heim  >  Artikel  >  php教程  >  Yii Framework-Analyse (4) – Detaillierte Analyse der Ausführungsfunktion von WebApplication

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

黄舟
黄舟Original
2016-12-27 11:15:441351Durchsuche

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));
}

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);
}

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;
    }
}

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)));
    }

$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);
}

$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);
}

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();
    }
}

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);
}

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;
    }
}

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;
}

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)));
}

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))));
    }
}

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_);
}

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;
}

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;
}

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). !


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