PHP-Yaf執(zhí)行流程-源碼分析

介紹

Yaf框架是一個(gè)c語言編寫的PHP框架,是一個(gè)以PHP擴(kuò)展形式提供的PHP開發(fā)框架小腊,相比于一般的PHP框架, 它更快久窟,更輕便秩冈,內(nèi)存占用率更低,就是本著對(duì)性能的追求斥扛,Yaf把框架中不易變的部分抽象出來入问,類如路由、自動(dòng)加載稀颁、bootstrap芬失、分發(fā)等,采用PHP擴(kuò)展去實(shí)現(xiàn)匾灶,以此來保證性能棱烂。

Yaf優(yōu)點(diǎn)
  • 用c語言開發(fā)的PHP框架,相比原生的PHP阶女,幾乎不會(huì)帶來額外的性能開銷
  • 所有的框架類颊糜,不需要編譯,在PHP啟動(dòng)的時(shí)候加載张肾,并常駐內(nèi)存.
  • 更快的執(zhí)行速度芭析,更少的內(nèi)存占用.
  • 靈巧的自動(dòng)加載. 支持全局和局部?jī)煞N加載規(guī)則, 方便類庫(kù)共享.
yaf缺點(diǎn)
  • 維護(hù)成本高锚扎,要維護(hù)PHP擴(kuò)展吞瞪,需要熟練C開發(fā)和Zend Api.
  • 目標(biāo)用戶群小,現(xiàn)在國(guó)內(nèi)很多中小型站都是使用虛擬主機(jī)驾孔,并不能隨意的給PHP添加擴(kuò)展.
  • 不像其他框架一樣提供各種豐富功能的類庫(kù)和各種優(yōu)雅的寫法芍秆,它只提供一個(gè)MVC的基本骨架.

Yaf框架執(zhí)行流程圖

引用官方流程圖

流程圖說明

在application目錄下有個(gè)Bootstrap.php文件,這個(gè)就是圖中的第一個(gè)環(huán)節(jié)翠勉,如果存在Bootstrap()就會(huì)先執(zhí)行該文件妖啥,該文件包含了一系列的初始化環(huán)節(jié),并返回一個(gè)Yaf_Application對(duì)象对碌,緊接著調(diào)用了它的run方法荆虱,run里面包含了圖中所有環(huán)節(jié),run首先是調(diào)用路由,路由的主要目的其實(shí)就是找到controllers文件怀读,然后執(zhí)行里面的init和action方法诉位,或者找到所有actions的地址然后加載,在去執(zhí)行對(duì)應(yīng)的execute方法菜枷,如果設(shè)置了autoRender在返回的時(shí)候會(huì)執(zhí)行render方法苍糠,就是view自動(dòng)渲染,圖中有六個(gè)雙橫線標(biāo)出的環(huán)節(jié)啤誊,就是六個(gè)插件方法岳瞭,用戶可以自定義實(shí)現(xiàn)這幾個(gè)方法,然后Yaf框架會(huì)在圖中相應(yīng)的步驟處調(diào)用對(duì)應(yīng)的HOOK方法蚊锹。

Yaf框架目錄結(jié)構(gòu)

+ public
  |- index.php //入口文件
  |- .htaccess //重寫規(guī)則    
  |+ css
  |+ img
  |+ js
+ conf
  |- application.ini //配置文件   
+ application 
  |+ actions //可將controller里面的方法單獨(dú)抽出來做為一個(gè)類實(shí)現(xiàn)
     |+ index
        |- Main.php
  |+ controllers
     |- Index.php //默認(rèn)控制器
  |+ views    
     |+ index   //控制器
        |- index.phtml //默認(rèn)視圖
  |+ modules //可以按模塊來區(qū)分不同業(yè)務(wù)下的控制器層
     |+ admin 
        |+ controllers 
           |- Index.php 
  |+ library //本地類庫(kù)
  |+ models  //model目錄
      |- baseModel.php
  |+ plugins //插件目錄
      |- testPlugin.php
  Bootstrap.php  引導(dǎo)文件

Yaf配置項(xiàng)說明

  • php.ini 配置項(xiàng)
選項(xiàng)名稱 默認(rèn)值 說明
yaf.environ product 環(huán)境名稱, 當(dāng)用INI作為Yaf的配置文件時(shí), 這個(gè)指明了Yaf將要在INI配置中讀取的節(jié)的名字
yaf.library NULL 全局類庫(kù)的目錄路徑
yaf.cache_config 0 是否緩存配置文件(只針對(duì)INI配置文件生效), 打開此選項(xiàng)可在復(fù)雜配置的情況下提高性能
yaf.name_suffix 1 在處理Controller, Action, Plugin, Model的時(shí)候, 類名中關(guān)鍵信息是否是后綴式, 比如UserModel, 而在前綴模式下則是ModelUser
yaf.name_separator "" 在處理Controller, Action, Plugin, Model的時(shí)候, 前綴和名字之間的分隔符, 默認(rèn)為空, 也就是UserPlugin, 加入設(shè)置為"_", 則判斷的依據(jù)就會(huì)變成:"User_Plugin", 這個(gè)主要是為了兼容ST已有的命名規(guī)范
yaf.forward_limit 5 forward最大嵌套深度
yaf.use_namespace 0 開啟的情況下, Yaf將會(huì)使用命名空間方式注冊(cè)自己的類, 比如Yaf_Application將會(huì)變成Yaf\Application
yaf.use_spl_autoload 0 開啟的情況下, Yaf在加載不成功的情況下, 會(huì)繼續(xù)讓PHP的自動(dòng)加載函數(shù)加載, 從性能考慮, 除非特殊情況, 否則保持這個(gè)選項(xiàng)關(guān)閉
//php.ini
[Yaf]
yaf.library = "c:/huan"
yaf.name_suffix = 0
yaf.name_separator = "_"
yaf.environ = "product"
  • application.ini 配置項(xiàng)
選項(xiàng)名稱 默認(rèn)值 說明
application.ext php PHP腳本的擴(kuò)展名
application.bootstrap Bootstrapplication.php Bootstrap路徑(絕對(duì)路徑)
application.library application.directory + "/library" 本地(自身)類庫(kù)的絕對(duì)目錄地址
application.baseUri NULL 在路由中, 需要忽略的路徑前綴, 一般不需要設(shè)置, Yaf會(huì)自動(dòng)判斷.
application.dispatcher.defaultModule index 默認(rèn)的模塊
application.dispatcher.throwException True 在出錯(cuò)的時(shí)候, 是否拋出異常
application.dispatcher.catchException False 是否使用默認(rèn)的異常捕獲Controller, 如果開啟, 在有未捕獲的異常的時(shí)候, 控制權(quán)會(huì)交給ErrorController的errorAction方法, 可以通過$request->getException()獲得此異常對(duì)象
application.dispatcher.defaultController index 默認(rèn)的控制器
application.dispatcher.defaultAction index 默認(rèn)的動(dòng)作
application.view.ext phtml 視圖模板擴(kuò)展名
application.modules modules 聲明存在的模塊名, 請(qǐng)注意, 如果你要定義這個(gè)值, 一定要定義Index Module
//application.ini
[mysql]
mysql.master.user_name = word
mysql.master.pass_word = 1234
mysql.slave.user_name = word
mysql.slave.pass_word = 1234

[database : mysql]
database.master.host = 127.0.0.1
database.slave.host  = 127.0.0.2,127.0.0.3

[product : database]
yaf.directory = APP_PATH "/app/" 
yaf.libray = APP_PATH "/libray/

可以看到在application.ini配置文件里面除了配置框架本身的配置項(xiàng)瞳筏,還可以添加一些我們自定義的配置項(xiàng),同時(shí)支持繼承配置功能枫耳,在框架啟動(dòng)的時(shí)候會(huì)根據(jù)yaf.environ設(shè)定的節(jié)點(diǎn)名字去讀取.

配置文件解析完畢后讀取到內(nèi)存的狀態(tài)

Yaf_Config_Ini Object
(
    [_config:protected] => Array
        (
            [mysql] => Array
                (
                    [master] => Array
                        (
                            [user_name] => word
                        )

                    [slave] => Array
                        (
                            [user_name] => word
                        )

                )

            [database] => Array
                (
                    [master] => Array
                        (
                            [host] => 127.0.0.1
                        )

                    [slave] => Array
                        (
                            [host] => 127.0.0.2,127.0.0.3
                        )

                )

            [yaf] => Array
                (
                    [directory] => C:\huan\apache\htdocs\yaf/app/
                    [libray] => C:\huan\apache\htdocs\yaf/libray/
                )

        )

    [_readonly:protected] => 1
)

調(diào)用Yaf框架

//入口文件index.php
define("APP_PATH",  '/home/test/yaf'); 
$app  = new Yaf_Application(APP_PATH . "/conf/application.ini");
$app->bootstrap()->run();

Bootstrap.php 類文件

class Bootstrap extends Yaf_Bootstrap_Abstract{

        public function _initConfig(Yaf_Dispatcher $dispatcher) {
                //存放全局?jǐn)?shù)據(jù)
                $config = Yaf_Application::app()->getConfig();
                Yaf_Registry::set("config", $config);
                //讀取配置
                $dispatcher->getConfig()->get('database')->master->host
                 //關(guān)閉自動(dòng)渲染
                $dispatcher->autoRender(false);
                //設(shè)置自定的模板引擎類如smarty
                $dispatcher->setView( Yaf_View_Interface  $request );
        }

        public function _initDefaultName(Yaf_Dispatcher $dispatcher) {
                $dispatcher->setDefaultModule("Index")->setDefaultController("Index")->setDefaultAction("index");
        }
       
        public function _initPlugin(Yaf_Dispatcher $dispatcher){
               //注冊(cè)插件
               $objPlugin = new  Test_Plugin();
               $dispatcher->registerPlugin($objPlugin);
        }

        public function _initRegistLocalLib(Yaf_Dispatcher $dispatcher){
              //注冊(cè)本地類前綴, 是的對(duì)于以這些前綴開頭的本地類, 都從本地類庫(kù)路徑中加載.
              Yaf_Loader::getInstance()->registerLocalNamespace(array('Foo','Msn'));
        }
}

Plugin.php 插件類文件

  class Test_Plugin extends Yaf_Plugin_Abstract {

       public function routerStartup(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {
       }

       public function routerShutdown(Yaf_Request_Abstract $request, Yaf_Response_Abstract $response) {
       }
  }

Controller.php 類文件

class Index_Controller extends Yaf_Controller_Abstract {
   
   //第二種action實(shí)現(xiàn)方式
   public $actions = array(
        'one' => 'actions/index/One.php',
        'two' => 'actions/index/Two.php',
   );
   
   //初始化方法
   public function ini(){

   }

   //第一種action實(shí)現(xiàn)方式
   public function index_Action() { 
       $this->getView()->assign("content", "Hello World");
       $this->getView()->display();
   }
}

Action.php 類文件

  Class One_Action extends Yaf_Action_Abstract{
         public function execute(){

         }
  }

Model 類文件

    class Base_Model {
          public function getDataList(){
          }
    }

注意: Yaf并沒有實(shí)現(xiàn)Model層乏矾,需要自己實(shí)現(xiàn)或者調(diào)用現(xiàn)成的Model庫(kù).

擴(kuò)展-核心功能模塊實(shí)現(xiàn)

擴(kuò)展 Yaf_Application 類注冊(cè)

YAF_STARTUP_FUNCTION(application) {  //宏替換一下 ZEND_MINIT_FUNCTION(yaf_##module)
    //PHP內(nèi)核中對(duì)PHP類的實(shí)現(xiàn)是通過zend_class_entry結(jié)構(gòu)體實(shí)現(xiàn)的
    zend_class_entry ce;
    //相當(dāng)于對(duì)ce初始化,指定一個(gè)類名稱 Ap_Application
    //指定類的成員方法列表 ap_application_methods 結(jié)構(gòu)體數(shù)組指針
    YAF_INIT_CLASS_ENTRY(ce, "Yaf_Application", "Yaf\\Application", yaf_application_methods);
    //向PHP注冊(cè)類迁杨,PHP中由class_table維護(hù)全局的類數(shù)組
    //可以簡(jiǎn)單理解為把類添加到這個(gè)數(shù)組中钻心,這樣就可以在
    //PHP中找到這個(gè)類了,內(nèi)核中有一組類似的注冊(cè)函數(shù)
    //用來注冊(cè)接口铅协、類捷沸、子類、接口實(shí)現(xiàn)狐史、抽象類等
    yaf_application_ce = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
    //指定類的屬性
    yaf_application_ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
    //設(shè)置類內(nèi)部的一些變量和屬性
    zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_CONFIG),     ZEND_ACC_PROTECTED TSRMLS_CC);
    zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER),     ZEND_ACC_PROTECTED TSRMLS_CC);
    zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_APP),        ZEND_ACC_STATIC | ZEND_ACC_PROTECTED TSRMLS_CC);
    zend_declare_property_null(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_MODULES),    ZEND_ACC_PROTECTED TSRMLS_CC);

    zend_declare_property_bool(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_RUN),    0,      ZEND_ACC_PROTECTED TSRMLS_CC);
    zend_declare_property_string(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_ENV),  YAF_G(environ), ZEND_ACC_PROTECTED TSRMLS_CC);

    zend_declare_property_long(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_ERRNO),      0,  ZEND_ACC_PROTECTED TSRMLS_CC);
    zend_declare_property_string(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_ERRMSG),   "",     ZEND_ACC_PROTECTED TSRMLS_CC);
    //內(nèi)核中有一組這樣的屬性標(biāo)記來指定類和變量的性質(zhì)
    /* method flags (types) 
       #define ZEND_ACC_STATIC            0x01
       #define ZEND_ACC_ABSTRACT        0x02
       #define ZEND_ACC_FINAL            0x04
       #define ZEND_ACC_IMPLEMENTED_ABSTRACT        0x08
       class flags (types) 
       #define ZEND_ACC_IMPLICIT_ABSTRACT_CLASS    0x10
       #define ZEND_ACC_EXPLICIT_ABSTRACT_CLASS    0x20
       #define ZEND_ACC_FINAL_CLASS                0x40 
       #define ZEND_ACC_INTERFACE                    0x80 */
    return SUCCESS;
}

//類成員函數(shù)的聲明
zend_function_entry yaf_application_methods[] = {
    PHP_ME(yaf_application, __construct,        yaf_application_construct_arginfo,  ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
    PHP_ME(yaf_application, run,            yaf_application_run_arginfo,        ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, execute,        yaf_application_execute_arginfo,    ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, app,            yaf_application_app_arginfo,        ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
    YAF_ME(yaf_application_environ, "environ",  yaf_application_environ_arginfo,    ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, bootstrap,          yaf_application_bootstrap_arginfo,      ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, getConfig,          yaf_application_getconfig_arginfo,  ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, getModules,         yaf_application_getmodule_arginfo,      ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, getDispatcher,      yaf_application_getdispatch_arginfo,    ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, setAppDirectory,    yaf_application_setappdir_arginfo,      ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, getAppDirectory,    yaf_application_void_arginfo,       ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, getLastErrorNo,     yaf_application_void_arginfo,       ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, getLastErrorMsg,    yaf_application_void_arginfo,       ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, clearLastError,     yaf_application_void_arginfo,       ZEND_ACC_PUBLIC)
    PHP_ME(yaf_application, __destruct,     NULL,                   ZEND_ACC_PUBLIC | ZEND_ACC_DTOR)
    PHP_ME(yaf_application, __clone,        NULL,                   ZEND_ACC_PRIVATE | ZEND_ACC_CLONE)
    PHP_ME(yaf_application, __sleep,        NULL,                   ZEND_ACC_PRIVATE)
    PHP_ME(yaf_application, __wakeup,       NULL,                   ZEND_ACC_PRIVATE)
    {NULL, NULL, NULL}
};

上面這個(gè)就是在擴(kuò)展里面注冊(cè)一個(gè)類的實(shí)現(xiàn)痒给,Yaf其他的類文件在注冊(cè)類的時(shí)候也幾乎和上面方式一致,具體看下源碼就可以了骏全,下面將從實(shí)例化一個(gè)Yaf_Application類開始分析苍柏。

擴(kuò)展 Yaf_Application 類構(gòu)造函數(shù) __construct 實(shí)現(xiàn)

PHP_METHOD(yaf_application, __construct) {
    yaf_config_t        *zconfig;
    yaf_request_t       *request;
    yaf_dispatcher_t    *zdispatcher;
    yaf_application_t   *app, *self;
    yaf_loader_t        *loader;
    zval            *config;
    zval            *section = NULL;
    //獲取yaf_application::_app變量值,默認(rèn)為0
    app  = zend_read_static_property(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_APP), 1 TSRMLS_CC);

#if PHP_YAF_DEBUG
    php_error_docref(NULL TSRMLS_CC, E_STRICT, "Yaf is running in debug mode");
#endif
    //如果app有值則報(bào)錯(cuò),也就是當(dāng)前類只能被實(shí)例化一次
    if (!ZVAL_IS_NULL(app)) {
        yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "Only one application can be initialized");
        RETURN_FALSE;
    }
    //獲取當(dāng)前的對(duì)象姜贡,也就是php里面的$this
    self = getThis();
    //獲取參數(shù)试吁,把配置文件路徑或者配置數(shù)組傳遞進(jìn)來
    //section配置文件中的節(jié)點(diǎn)名字,默認(rèn)product
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &config, &section) == FAILURE) {
        YAF_UNINITIALIZED_OBJECT(getThis());
        return;
    }
    
    if (!section || Z_TYPE_P(section) != IS_STRING || !Z_STRLEN_P(section)) {
        MAKE_STD_ZVAL(section);
        ZVAL_STRING(section, YAF_G(environ), 0);
        //獲取config對(duì)象
        zconfig = yaf_config_instance(NULL, config, section TSRMLS_CC);
        efree(section);
    } else {
        //獲取config對(duì)象
        zconfig = yaf_config_instance(NULL, config, section TSRMLS_CC);
    }
    //解析配置文件楼咳,并將配置信息保存在zconfig對(duì)象中
    if  (zconfig == NULL
            || Z_TYPE_P(zconfig) != IS_OBJECT
            || !instanceof_function(Z_OBJCE_P(zconfig), yaf_config_ce TSRMLS_CC)
            || yaf_application_parse_option(zend_read_property(yaf_config_ce,
                    zconfig, ZEND_STRL(YAF_CONFIG_PROPERT_NAME), 1 TSRMLS_CC) TSRMLS_CC) == FAILURE) {
        YAF_UNINITIALIZED_OBJECT(getThis());
        yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "Initialization of application config failed");
        RETURN_FALSE;
    }
    //獲取 request 對(duì)象熄捍,請(qǐng)求的信息保存在里面
    request = yaf_request_instance(NULL, YAF_G(base_uri) TSRMLS_CC);
    if (YAF_G(base_uri)) {
        efree(YAF_G(base_uri));
        YAF_G(base_uri) = NULL;
    }

    if (!request) {
        YAF_UNINITIALIZED_OBJECT(getThis());
        yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "Initialization of request failed");
        RETURN_FALSE;
    }
    //獲取dispatcher對(duì)象,主要在里面調(diào)用插件母怜、路由余耽、分發(fā)等
    zdispatcher = yaf_dispatcher_instance(NULL TSRMLS_CC);
    if (NULL == zdispatcher
            || Z_TYPE_P(zdispatcher) != IS_OBJECT
            || !instanceof_function(Z_OBJCE_P(zdispatcher), yaf_dispatcher_ce TSRMLS_CC)) {
        YAF_UNINITIALIZED_OBJECT(getThis());
        yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "Instantiation of application dispatcher failed");
        RETURN_FALSE;
    }
    //把request對(duì)象保存在zdispatcher對(duì)像屬性中
    yaf_dispatcher_set_request(zdispatcher, request TSRMLS_CC);
    //保存zconfig對(duì)象到當(dāng)前yaf_application對(duì)象屬性中
    zend_update_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_CONFIG), zconfig TSRMLS_CC);
    //保存zdispatcher對(duì)象到當(dāng)前yaf_application對(duì)象屬性中
    zend_update_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER), zdispatcher TSRMLS_CC);

    zval_ptr_dtor(&request);
    zval_ptr_dtor(&zdispatcher);
    zval_ptr_dtor(&zconfig);
    //是否指定本地類庫(kù)地址
    if (YAF_G(local_library)) {
        //獲取一個(gè)load加載類,并同時(shí)向內(nèi)核注冊(cè)一個(gè)自動(dòng)加載器__autoload
        //之后在代碼中new class()都會(huì)調(diào)用擴(kuò)展中注冊(cè)的自動(dòng)加載器
        loader = yaf_loader_instance(NULL, YAF_G(local_library),
                strlen(YAF_G(global_library))? YAF_G(global_library) : NULL TSRMLS_CC);
        efree(YAF_G(local_library));
        YAF_G(local_library) = NULL;
    } else {
        char *local_library;
        //獲取一個(gè)默認(rèn)的本地類庫(kù)地址
        spprintf(&local_library, 0, "%s%c%s", YAF_G(directory), DEFAULT_SLASH, YAF_LIBRARY_DIRECTORY_NAME);
        //同上面解釋一致
        loader = yaf_loader_instance(NULL, local_library,
                strlen(YAF_G(global_library))? YAF_G(global_library) : NULL TSRMLS_CC);
        efree(local_library);
    }

    if (!loader) {
        YAF_UNINITIALIZED_OBJECT(getThis());
        yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "Initialization of application auto loader failed");
        RETURN_FALSE;
    }
       
    //賦值對(duì)象屬性
    zend_update_property_bool(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_RUN), 0 TSRMLS_CC);
    zend_update_property_string(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_ENV), YAF_G(environ) TSRMLS_CC);
    
    //這個(gè)modules一定會(huì)存在苹熏,默認(rèn)是Index
    if (YAF_G(modules))  {
        zend_update_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_MODULES), YAF_G(modules) TSRMLS_CC);
        Z_DELREF_P(YAF_G(modules));
        YAF_G(modules) = NULL;
    } else {
        zend_update_property_null(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_MODULES) TSRMLS_CC);
    }
    //yaf_application::_app 賦值成當(dāng)前self對(duì)象
    zend_update_static_property(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_APP), self TSRMLS_CC);
}

PHP_METHOD(Yaf_application, bootstrap) 擴(kuò)展實(shí)現(xiàn)

PHP_METHOD(yaf_application, bootstrap) {
    char            *bootstrap_path;
    uint            len, retval = 1;
    zend_class_entry    **ce;
    yaf_application_t   *self = getThis();
    //判斷 Bootstrap 類是否存在碟贾,默認(rèn)第一次肯定不存在
    //因?yàn)檫€沒有加載注冊(cè)進(jìn)來
    if (zend_hash_find(EG(class_table), YAF_DEFAULT_BOOTSTRAP_LOWER, YAF_DEFAULT_BOOTSTRAP_LEN, (void **) &ce) != SUCCESS) {
        //判斷是否指定了bootstrap文件路徑
        if (YAF_G(bootstrap)) {
            bootstrap_path  = estrdup(YAF_G(bootstrap));
            len = strlen(YAF_G(bootstrap));
        } else {
            //沒有指定則使用默認(rèn)路徑
            len = spprintf(&bootstrap_path, 0, "%s%c%s.%s", YAF_G(directory), DEFAULT_SLASH, YAF_DEFAULT_BOOTSTRAP, YAF_G(ext));
        }
        //導(dǎo)入bootstrap文件币喧,內(nèi)核如果發(fā)現(xiàn)是類,則會(huì)自動(dòng)注冊(cè)上
        if (!yaf_loader_import(bootstrap_path, len + 1, 0 TSRMLS_CC)) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't find bootstrap file %s", bootstrap_path);
            retval = 0;
        //獲取 bootstrap 類
        } else if (zend_hash_find(EG(class_table), YAF_DEFAULT_BOOTSTRAP_LOWER, YAF_DEFAULT_BOOTSTRAP_LEN, (void **) &ce) != SUCCESS)  {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't find class %s in %s", YAF_DEFAULT_BOOTSTRAP, bootstrap_path);
            retval = 0;
        //判斷該類是否繼承Yaf_Bootstrap_Abstract
        } else if (!instanceof_function(*ce, yaf_bootstrap_ce TSRMLS_CC)) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Expect a %s instance, %s give", yaf_bootstrap_ce->name, (*ce)->name);
            retval = 0;
        }

        efree(bootstrap_path);
    }

    if (!retval) {
        RETURN_FALSE;
    } else {
        zval            *bootstrap;
        HashTable       *methods;
        yaf_dispatcher_t    *dispatcher;
        //實(shí)例化一個(gè)bootstrap對(duì)象
        MAKE_STD_ZVAL(bootstrap);
        object_init_ex(bootstrap, *ce);
        //獲取dispatcher 對(duì)象
        dispatcher = zend_read_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER), 1 TSRMLS_CC);
        //獲取bootstrap類里面所有的方法袱耽,每個(gè)類都用一個(gè)函數(shù)表function_table來記錄
        //方法名和對(duì)應(yīng)結(jié)構(gòu)體指針
        methods = &((*ce)->function_table);
        //循環(huán)bootstrap類里面所有的方法
        //內(nèi)核中對(duì)array的實(shí)現(xiàn)是通過hash_table實(shí)現(xiàn)的粱锐,內(nèi)核中會(huì)
        //看到到處使用hash_table的地方,可以簡(jiǎn)單理解為數(shù)組的操作
        for(zend_hash_internal_pointer_reset(methods);
                zend_hash_has_more_elements(methods) == SUCCESS;
                zend_hash_move_forward(methods)) {
            char *func;
            uint len;
            ulong idx;
            //獲取第一個(gè)方法名字
            zend_hash_get_current_key_ex(methods, &func, &len, &idx, 0, NULL);
            /* cann't use ZEND_STRL in strncasecmp, it cause a compile failed in VS2009 */
            #define YAF_BOOTSTRAP_INITFUNC_PREFIX   "_init"
            //Bootstrap類實(shí)現(xiàn)了一系列的_init開頭的方法
            //這里是比較函數(shù)func是否以_init開頭
            if (strncasecmp(func, YAF_BOOTSTRAP_INITFUNC_PREFIX, sizeof(YAF_BOOTSTRAP_INITFUNC_PREFIX)-1)) {
                continue;
            }
            //調(diào)用所有以_init開頭的函數(shù)扛邑,入?yún)⒔y(tǒng)一為dispatcher對(duì)象
            zend_call_method(&bootstrap, *ce, NULL, func, len - 1, NULL, 1, dispatcher, NULL TSRMLS_CC);
            /** an uncaught exception threw in function call */
            if (EG(exception)) {
                zval_ptr_dtor(&bootstrap);
                RETURN_FALSE;
            }
        }

        zval_ptr_dtor(&bootstrap);
    }
    //最后會(huì)返回application對(duì)象自身
    RETVAL_ZVAL(self, 1, 0);
}

PHP_METHOD(yaf_application, run) 擴(kuò)展實(shí)現(xiàn)

PHP_METHOD(yaf_application, run) {
    zval *running;
    yaf_dispatcher_t  *dispatcher;
    yaf_response_t    *response;
    yaf_application_t *self = getThis();
        
    //獲取屬性值怜浅,默認(rèn)第一次為0
    running = zend_read_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_RUN), 1 TSRMLS_CC);
    if (IS_BOOL == Z_TYPE_P(running)
            && Z_BVAL_P(running)) {
        yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "An application instance already run");
        RETURN_TRUE;
    }
    //賦值為1,可以看出來當(dāng)前application對(duì)象中的run函數(shù)只能被調(diào)用一次
    ZVAL_BOOL(running, 1);
    zend_update_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_RUN), running TSRMLS_CC);
    //獲取dispatcher對(duì)象
    dispatcher = zend_read_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER), 1 TSRMLS_CC);
    //進(jìn)行路由分發(fā)等工作
    if ((response = yaf_dispatcher_dispatch(dispatcher TSRMLS_CC))) {
        RETURN_ZVAL(response, 1, 1);
    }

    RETURN_FALSE;
}

yaf_dispatcher_dispatch() 方法里面主要分兩部分蔬崩,路由+分發(fā)恶座,其中夾雜著一些插件調(diào)用,就是上圖中雙橫線標(biāo)出的環(huán)節(jié)沥阳,先看下官方對(duì)插件的說明跨琳。

觸發(fā)順序 名稱 觸發(fā)時(shí)機(jī)
1 routerStartup 在路由之前觸發(fā)
2 routerShutdown 路由結(jié)束之后觸發(fā)
3 dispatchLoopStartup 分發(fā)循環(huán)開始之前被觸發(fā)
4 preDispatch 分發(fā)之前觸發(fā)
5 postDispatch 分發(fā)結(jié)束之后觸發(fā)
6 dispatchLoopShutdown 分發(fā)循環(huán)結(jié)束之后觸發(fā)

擴(kuò)展中插件方法名用宏表示

#define YAF_PLUGIN_HOOK_ROUTESTARTUP                "routerstartup"
#define YAF_PLUGIN_HOOK_ROUTESHUTDOWN           "routershutdown"
#define YAF_PLUGIN_HOOK_LOOPSTARTUP             "dispatchloopstartup"
#define YAF_PLUGIN_HOOK_PREDISPATCH                 "predispatch"
#define YAF_PLUGIN_HOOK_POSTDISPATCH                "postdispatch"
#define YAF_PLUGIN_HOOK_LOOPSHUTDOWN                "dispatchloopshutdown"
#define YAF_PLUGIN_HOOK_PRERESPONSE             "preresponse"

yaf_dispatcher_dispatch(yaf_dispatcher_t *dispatcher TSRMLS_DC)

yaf_response_t * yaf_dispatcher_dispatch(yaf_dispatcher_t *dispatcher TSRMLS_DC) {
    zval *return_response, *plugins, *view;
    yaf_response_t *response;
    yaf_request_t *request;
    uint nesting = YAF_G(forward_limit);
    //獲取response對(duì)象
    response = yaf_response_instance(NULL, sapi_module.name TSRMLS_CC);
    //獲取request對(duì)象
    request  = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_REQUEST), 1 TSRMLS_CC);
    //獲取插件數(shù)組對(duì)象,這是一個(gè)數(shù)組桐罕,里面每個(gè)值都是一個(gè)插件對(duì)象
    //但前提是我們創(chuàng)建插件類脉让,實(shí)例化之后,注冊(cè)進(jìn)dispatcher對(duì)象里
    plugins  = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_PLUGINS), 1 TSRMLS_CC);
    //如果不是對(duì)象則報(bào)錯(cuò)
    if (IS_OBJECT != Z_TYPE_P(request)) {
        yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "Expect a %s instance", yaf_request_ce->name);
        zval_ptr_dtor(&response);
        return NULL;
    }

    /* route request */
    //是否已經(jīng)路由過
    if (!yaf_request_is_routed(request TSRMLS_CC)) {
        //調(diào)用插件routerstartup方法功炮,如果注冊(cè)的情況
        YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_ROUTESTARTUP, request, response);
        //捕獲異常 Error_Controller溅潜,開啟的情況下,對(duì)應(yīng)配置項(xiàng)為 catchException
        YAF_EXCEPTION_HANDLE(dispatcher, request, response);
        //進(jìn)行路由薪伏,就是找到 controller滚澜、action、model
        if (!yaf_dispatcher_route(dispatcher, request TSRMLS_CC)) {
           //拋出異常
            yaf_trigger_error(YAF_ERR_ROUTE_FAILED TSRMLS_CC, "Routing request failed");
            //捕獲異常 Error_Controller
            YAF_EXCEPTION_HANDLE_NORET(dispatcher, request, response);
            zval_ptr_dtor(&response);
            return NULL;
        }
        //設(shè)置Controller嫁怀、action设捐、model
        yaf_dispatcher_fix_default(dispatcher, request TSRMLS_CC);
        //調(diào)用插件routerShutdown方法
        YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_ROUTESHUTDOWN, request, response);
        //捕獲異常
        YAF_EXCEPTION_HANDLE(dispatcher, request, response);
        //已經(jīng)路由完畢標(biāo)識(shí)
        (void)yaf_request_set_routed(request, 1 TSRMLS_CC);
    } else {
        //設(shè)置Controller、action塘淑、model
        yaf_dispatcher_fix_default(dispatcher, request TSRMLS_CC);
    }
    //調(diào)用插件dispatchLoopStartup方法
    YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_LOOPSTARTUP, request, response);
    //捕獲異常
    YAF_EXCEPTION_HANDLE(dispatcher, request, response);
    //獲取view對(duì)象
    view = yaf_dispatcher_init_view(dispatcher, NULL, NULL TSRMLS_CC);
    if (!view) {
        return NULL;
    }

    do {
        //調(diào)用插件preDispatch方法
        YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_PREDISPATCH, request, response);
        //捕獲異常
        YAF_EXCEPTION_HANDLE(dispatcher, request, response);
        //開始分發(fā)
        if (!yaf_dispatcher_handle(dispatcher, request, response, view TSRMLS_CC)) {
            YAF_EXCEPTION_HANDLE(dispatcher, request, response);
            zval_ptr_dtor(&response);
            return NULL;
        }
        yaf_dispatcher_fix_default(dispatcher, request TSRMLS_CC);
        //調(diào)用插件postDispatch方法
        YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_POSTDISPATCH, request, response);
        //捕獲異常
        YAF_EXCEPTION_HANDLE(dispatcher, request, response);
        //這個(gè)就是控制分發(fā)次數(shù)萝招,配置項(xiàng)中的forward_limit
    } while (--nesting > 0 && !yaf_request_is_dispatched(request TSRMLS_CC));
    //調(diào)用插件dispatchLoopShutdown方法
    YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_LOOPSHUTDOWN, request, response);
    //捕獲異常
    YAF_EXCEPTION_HANDLE(dispatcher, request, response);
    //如果分發(fā)次數(shù)全部耗盡,且還有異常的話
    if (0 == nesting && !yaf_request_is_dispatched(request TSRMLS_CC)) {
        yaf_trigger_error(YAF_ERR_DISPATCH_FAILED TSRMLS_CC, "The max dispatch nesting %ld was reached", YAF_G(forward_limit));
        YAF_EXCEPTION_HANDLE_NORET(dispatcher, request, response);
        zval_ptr_dtor(&response);
        return NULL;
    }
    //最后返回一個(gè) response 對(duì)象
    return_response = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_RETURN), 1 TSRMLS_CC);

    if (!Z_BVAL_P(return_response)) {
        (void)yaf_response_send(response TSRMLS_CC);
        yaf_response_clear_body(response, NULL, 0 TSRMLS_CC);
    }

    return response;
}

yaf_dispatcher_route() 路由入口

int yaf_dispatcher_route(yaf_dispatcher_t *dispatcher, yaf_request_t *request TSRMLS_DC) {
    zend_class_entry *router_ce;
    //獲取路由器對(duì)象存捺,dispatcher初始化時(shí)會(huì)創(chuàng)建內(nèi)置路由器
    yaf_router_t *router = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_ROUTER), 1 TSRMLS_CC);
    if (IS_OBJECT == Z_TYPE_P(router)) {
        //是否內(nèi)置的路由器
        if ((router_ce = Z_OBJCE_P(router)) == yaf_router_ce) {
            //執(zhí)行路由器里面的路由協(xié)議
            yaf_router_route(router, request TSRMLS_CC);
        } else {
            //自定義路由器
            /* user custom router */
            zval *ret = zend_call_method_with_1_params(&router, router_ce, NULL, "route", &ret, request);
            if (Z_TYPE_P(ret) == IS_BOOL && Z_BVAL_P(ret) == 0) {
                yaf_trigger_error(YAF_ERR_ROUTE_FAILED TSRMLS_CC, "Routing request faild");
                return 0;
            }
        }
        return 1;
    }
    return 0;
}

這段代碼是路由環(huán)節(jié)的入口槐沼,dispatcher初始化時(shí)會(huì)創(chuàng)建內(nèi)置路由器,這里只涉及路由器概念召噩,上面的自定義并不是自定義路由協(xié)議母赵,而是你可以重新寫一個(gè)路由器逸爵,我們通常在項(xiàng)目中自定義路由協(xié)議就可以了具滴,沒有必要自己實(shí)現(xiàn)一個(gè)路由器。而且框架中其實(shí)也是寫死了內(nèi)置路由器师倔,沒有給你set自定義路由器的接口构韵。

yaf_router_route() 執(zhí)行路由

int yaf_router_route(yaf_router_t *router, yaf_request_t *request TSRMLS_DC) {
    zval        *routers, *ret;
    yaf_route_t **route;
    HashTable   *ht;
    //獲取路由協(xié)議,可以添加多層路由協(xié)議,類似于多重插件
    //通過addRoute方法向路由器注冊(cè)自己的路由協(xié)議疲恢,默認(rèn)的
    //路由協(xié)議是Yaf_Route_Static
    routers = zend_read_property(yaf_router_ce, router, ZEND_STRL(YAF_ROUTER_PROPERTY_NAME_ROUTES), 1 TSRMLS_CC);

    ht = Z_ARRVAL_P(routers);
    //for循環(huán)依次調(diào)用路由協(xié)議的route方法凶朗,成功則記下當(dāng)前
    //生效的這個(gè)路由協(xié)議的索引位置,并設(shè)置request為已路由
    //不成功則繼續(xù)調(diào)用下一個(gè)路由協(xié)議显拳。
    for(zend_hash_internal_pointer_end(ht);
            zend_hash_has_more_elements(ht) == SUCCESS;
            zend_hash_move_backwards(ht)) {

        if (zend_hash_get_current_data(ht, (void**)&route) == FAILURE) {
            continue;
        }
        //調(diào)用路由協(xié)議對(duì)象的route方法
        zend_call_method_with_1_params(route, Z_OBJCE_PP(route), NULL, "route", &ret, request);

        if (IS_BOOL != Z_TYPE_P(ret) || !Z_BVAL_P(ret)) {
            zval_ptr_dtor(&ret);
            continue;
        } else {
            char *key;
            uint len = 0;
            ulong idx = 0;
            //記錄當(dāng)前路由協(xié)議的索引
            switch(zend_hash_get_current_key_ex(ht, &key, &len, &idx, 0, NULL)) {
                case HASH_KEY_IS_LONG:
                    zend_update_property_long(yaf_router_ce, router, ZEND_STRL(YAF_ROUTER_PROPERTY_NAME_CURRENT_ROUTE), idx TSRMLS_CC);
                    break;
                case HASH_KEY_IS_STRING:
                    if (len) {
                        zend_update_property_string(yaf_router_ce, router, ZEND_STRL(YAF_ROUTER_PROPERTY_NAME_CURRENT_ROUTE), key TSRMLS_CC);
                    }
                    break;
            }
            //設(shè)置為已路由
            yaf_request_set_routed(request, 1 TSRMLS_CC);
            zval_ptr_dtor(&ret);
            break;
        }
    }
    return 1;
}

內(nèi)置的路由協(xié)議

上面幾種路由協(xié)議源代碼列表

yaf_route_static.c
yaf_route_simple.c
yaf_route_supervar.c
yaf_route_rewrite.c
yaf_route_regex.c
yaf_route_map.c

無路是哪個(gè)路由協(xié)議最后功能都是為了設(shè)置module棚愤,controller,action的名稱

yaf_dispatcher_handle() 開始分發(fā)

//只看下主邏輯 
int yaf_dispatcher_handle(yaf_dispatcher_t *dispatcher, yaf_request_t *request,  yaf_response_t *response, yaf_view_t *view TSRMLS_DC) {

    zend_class_entry *request_ce;
    //代碼根目錄
    char *app_dir = YAF_G(directory);

    request_ce = Z_OBJCE_P(request);
    //代表request開始杂数,如果出現(xiàn)異常宛畦,則會(huì)在把當(dāng)前狀態(tài)改成0
    //在分發(fā)循環(huán)while會(huì)判斷這個(gè)值,如果為0則代表之前分發(fā)中
    //存在異常所以保證在分發(fā)forward_limit次數(shù)內(nèi)再繼續(xù)分發(fā)
    //如果等于1則代表沒有異常情況揍移,分發(fā)完畢.
    yaf_request_set_dispatched(request, 1 TSRMLS_CC);
    if (!app_dir) {
        yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "%s requires %s(which set the application.directory) to be initialized first",
                yaf_dispatcher_ce->name, yaf_application_ce->name);
        return 0;
    } else {
        int is_def_module = 0;
        /* int is_def_ctr = 0; */
        zval *module, *controller, *dmodule, /* *dcontroller,*/ *instantly_flush;
        zend_class_entry *ce;
        yaf_controller_t *executor;
        zend_function    *fptr;
        //獲取module
        module      = zend_read_property(request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_MODULE), 1 TSRMLS_CC);
        //獲取controller
        controller  = zend_read_property(request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_CONTROLLER), 1 TSRMLS_CC);
        //獲取默認(rèn)module默認(rèn)為Index
        dmodule     = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_MODULE), 1 TSRMLS_CC);

        if (Z_TYPE_P(module) != IS_STRING
                || !Z_STRLEN_P(module)) {
            yaf_trigger_error(YAF_ERR_DISPATCH_FAILED TSRMLS_CC, "Unexcepted a empty module name");
            return 0;
        //判斷當(dāng)前請(qǐng)求的model是否在modules里面次和,默認(rèn)情況modules里面也是Index
        //如果自定義其他的model,就需要添加在modules這個(gè)選項(xiàng)里面那伐,添加的無論是
        //什么model都需要存在Index這個(gè)model踏施,類似于:Index,Admin,Main這樣,不添
        //加的話會(huì)提示錯(cuò)誤.
        } else if (!yaf_application_is_module_name(Z_STRVAL_P(module), Z_STRLEN_P(module) TSRMLS_CC)) {
            yaf_trigger_error(YAF_ERR_NOTFOUND_MODULE TSRMLS_CC, "There is no module %s", Z_STRVAL_P(module));
            return 0;
        }

        if (Z_TYPE_P(controller) != IS_STRING
                || !Z_STRLEN_P(controller)) {
            yaf_trigger_error(YAF_ERR_DISPATCH_FAILED TSRMLS_CC, "Unexcepted a empty controller name");
            return 0;
        }
        //判斷當(dāng)前的model是否等于默認(rèn)的model
        //如果等于就去默認(rèn)的Controllers目錄下找
        //控制器罕邀,如果不等于這個(gè)值就為0則就去
        //modules/model/controllers/下面找控制器
        //后面會(huì)有體現(xiàn)
        if (strncasecmp(Z_STRVAL_P(dmodule), Z_STRVAL_P(module), Z_STRLEN_P(module)) == 0) {
            is_def_module = 1;
        }
        //找到對(duì)應(yīng)的controller類
        ce = yaf_dispatcher_get_controller(app_dir, Z_STRVAL_P(module), Z_STRVAL_P(controller), Z_STRLEN_P(controller), is_def_module TSRMLS_CC);
        if (!ce) {
            return 0;
        } else {
            zval  *action, *render, *ret = NULL;
            char  *action_lower, *func_name, *view_dir;
            uint  func_name_len;

            yaf_controller_t *icontroller;
            //實(shí)例化controoller對(duì)象
            MAKE_STD_ZVAL(icontroller);
            object_init_ex(icontroller, ce);

            yaf_controller_construct(ce, icontroller, request, response, view, NULL TSRMLS_CC);
            if (EG(exception)) {
                zval_ptr_dtor(&icontroller);
                return 0;
            }
        
            //獲取view路徑畅形,如果這個(gè)is_def_module為1
            //則取默認(rèn)的views目錄,如果為0诉探,則取 modules/model/views 這個(gè)目錄
            if (is_def_module) {
                spprintf(&view_dir, 0, "%s%c%s", app_dir, DEFAULT_SLASH, "views");
            } else {
                spprintf(&view_dir, 0, "%s%c%s%c%s%c%s", app_dir, DEFAULT_SLASH, "modules", DEFAULT_SLASH, Z_STRVAL_P(module), DEFAULT_SLASH, "views");
            }

            if (YAF_G(view_directory)) {
                efree(YAF_G(view_directory));
            }
            YAF_G(view_directory) = view_dir;

            zend_update_property(ce, icontroller, ZEND_STRL(YAF_CONTROLLER_PROPERTY_NAME_NAME), controller TSRMLS_CC);
            
            //獲取action
            action       = zend_read_property(request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_ACTION), 1 TSRMLS_CC);
            action_lower = zend_str_tolower_dup(Z_STRVAL_P(action), Z_STRLEN_P(action));

            /* because the action might call the forward to override the old action */
            Z_ADDREF_P(action);
            //拼接一個(gè)action函數(shù)名
            func_name_len = spprintf(&func_name,  0, "%s%s", action_lower, "action");
            efree(action_lower);
            //判斷在controller對(duì)象里面是否有這個(gè)action函數(shù)束亏,如 indexaction
            if (zend_hash_find(&((ce)->function_table), func_name, func_name_len + 1, (void **)&fptr) == SUCCESS) {
                //省略......

                executor = icontroller;

                //如果存在這個(gè)action函數(shù)則調(diào)用
                zend_call_method(&icontroller, ce, NULL, func_name, func_name_len, &ret, 0, NULL, NULL TSRMLS_CC);
            
                efree(func_name);

                //省略......

            //如果不存在這個(gè)action函數(shù)則按第二種action方式去獲
            //取看看在這個(gè)controller里面是否存在actions變量,因
            //為有可能在這個(gè)actions數(shù)組變量里面記錄所有的action
            //類方法地址
            } else if ((ce = yaf_dispatcher_get_action(app_dir, icontroller,
                            Z_STRVAL_P(module), is_def_module, Z_STRVAL_P(action), Z_STRLEN_P(action) TSRMLS_CC))
                    && (zend_hash_find(&(ce)->function_table, YAF_ACTION_EXECUTOR_NAME,
                            sizeof(YAF_ACTION_EXECUTOR_NAME), (void **)&fptr) == SUCCESS)) {
                //省略......

                //實(shí)例化這個(gè)Action類
                MAKE_STD_ZVAL(iaction);
                object_init_ex(iaction, ce);
                executor = iaction;
                //省略......
                
                //調(diào)用這個(gè)Action類里面的execute方法阵具,可以看到這個(gè)方法是固定的
                zend_call_method_with_0_params(&iaction, ce, NULL, "execute", &ret);
                
                //省略......
            } else {
                efree(func_name);
                zval_ptr_dtor(&icontroller);
                return 0;
            }
            //下面這部分就是視圖view自動(dòng)渲染部分碍遍,不在詳細(xì)分析了
            if (executor) {
                int auto_render = 1;
                render = zend_read_property(ce, executor, ZEND_STRL(YAF_CONTROLLER_PROPERTY_NAME_RENDER), 1 TSRMLS_CC);
                instantly_flush = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_FLUSH), 1 TSRMLS_CC);
                if (render == EG(uninitialized_zval_ptr)) {
                    render = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_RENDER), 1 TSRMLS_CC);
                    auto_render = Z_BVAL_P(render);
                } else if (Z_TYPE_P(render) <= IS_BOOL && !Z_BVAL_P(render)) {
                    auto_render = 0;
                }
                //是否自動(dòng)渲染view
                if (auto_render) {
                    ret = NULL;
                    if (!Z_BVAL_P(instantly_flush)) {
                        zend_call_method_with_1_params(&executor, ce, NULL, "render", &ret, action);
                        zval_ptr_dtor(&executor);

                        if (!ret) {
                            zval_ptr_dtor(&action);
                            return 0;
                        } else if (IS_BOOL == Z_TYPE_P(ret) && !Z_BVAL_P(ret)) {
                            zval_ptr_dtor(&ret);
                            zval_ptr_dtor(&action);
                            return 0;
                        }

                        if (Z_TYPE_P(ret) == IS_STRING && Z_STRLEN_P(ret)) {
                            yaf_response_alter_body(response, NULL, 0, Z_STRVAL_P(ret), Z_STRLEN_P(ret), YAF_RESPONSE_APPEND  TSRMLS_CC);
                        } 

                        zval_ptr_dtor(&ret);
                    } else {
                        zend_call_method_with_1_params(&executor, ce, NULL, "display", &ret, action);
                        zval_ptr_dtor(&executor);

                        if (!ret) {
                            zval_ptr_dtor(&action);
                            return 0;
                        }

                        if ((Z_TYPE_P(ret) == IS_BOOL && !Z_BVAL_P(ret))) {
                            zval_ptr_dtor(&ret);
                            zval_ptr_dtor(&action);
                            return 0;
                        }
                        zval_ptr_dtor(&ret);
                    }
                } else {
                    zval_ptr_dtor(&executor);
                }
            }
            zval_ptr_dtor(&action);
        }
        return 1;
    }
return 0;
}

yaf_dispatcher_get_controller() 獲取 controller 類

zend_class_entry * yaf_dispatcher_get_controller(char* app_dir, char *module, char *controller, int len, int def_module TSRMLS_DC) {
    char     *directory     = NULL;
    int  directory_len  = 0;
        
    //這塊之前說過,如果def_module等于1走默認(rèn)的路徑
    //如果等于0則走modules下的路徑
    if (def_module) {
        // directory = app_dir/controllers
        directory_len = spprintf(&directory, 0, "%s%c%s", app_dir, DEFAULT_SLASH, YAF_CONTROLLER_DIRECTORY_NAME);
    } else {
        // directory = app_dir/modules/model/controllers
        directory_len = spprintf(&directory, 0, "%s%c%s%c%s%c%s", app_dir, DEFAULT_SLASH,
                YAF_MODULE_DIRECTORY_NAME, DEFAULT_SLASH, module, DEFAULT_SLASH, YAF_CONTROLLER_DIRECTORY_NAME);
    }
     
    if (directory_len) {
        char *class         = NULL;
        char *class_lowercase   = NULL;
        int class_len       = 0;
        zend_class_entry **ce   = NULL;
        // 這里根據(jù)配置區(qū)分前綴模式還是后綴模式 
        // Controller_Index 或者 Index_Controller 
        // ControllerIndex 或者 IndexController 
        if (YAF_G(name_suffix)) {
            class_len = spprintf(&class, 0, "%s%s%s", controller, YAF_G(name_separator), "Controller");
        } else {
            class_len = spprintf(&class, 0, "%s%s%s", "Controller", YAF_G(name_separator), controller);
        }
        //轉(zhuǎn)小寫
        class_lowercase = zend_str_tolower_dup(class, class_len);
       
        //是否存在這個(gè)Controller類
        if (zend_hash_find(EG(class_table), class_lowercase, class_len + 1, (void **)&ce) != SUCCESS) {
            //加載這個(gè)Controller類
            if (!yaf_internal_autoload(controller, len, &directory TSRMLS_CC)) {
                yaf_trigger_error(YAF_ERR_NOTFOUND_CONTROLLER TSRMLS_CC, "Failed opening controller script %s: %s", directory, strerror(errno));
                efree(class);
                efree(class_lowercase);
                efree(directory);
                return NULL;
            //獲取這個(gè)Controller類指針
            } else if (zend_hash_find(EG(class_table), class_lowercase, class_len + 1, (void **) &ce) != SUCCESS)  {
                yaf_trigger_error(YAF_ERR_AUTOLOAD_FAILED TSRMLS_CC, "Could not find class %s in controller script %s", class, directory);
                efree(class);
                efree(class_lowercase);
                efree(directory);
                return 0;
            //判斷是否繼承 Yaf_Controller_Abstract
            } else if (!instanceof_function(*ce, yaf_controller_ce TSRMLS_CC)) {
                yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "Controller must be an instance of %s", yaf_controller_ce->name);
                efree(class);
                efree(class_lowercase);
                efree(directory);
                return 0;
            }
        }

        efree(class);
        efree(class_lowercase);
        efree(directory);

        return *ce;
    }

    return NULL;
}

yaf_dispatcher_get_action() 獲取 action 類

zend_class_entry * yaf_dispatcher_get_action(char *app_dir, yaf_controller_t *controller, char *module, int def_module, char *action, int len TSRMLS_DC) {
    zval **ppaction, *actions_map;
    
    //獲取actions數(shù)組
    actions_map = zend_read_property(Z_OBJCE_P(controller), controller, ZEND_STRL(YAF_CONTROLLER_PROPERTY_NAME_ACTIONS), 1 TSRMLS_CC);

    if (IS_ARRAY == Z_TYPE_P(actions_map)) {
        zend_class_entry **ce;
        uint  class_len;
        char *class_name, *class_lowercase;
        char *action_upper = estrndup(action, len);
        //將action名字首字母轉(zhuǎn)為大寫
        *(action_upper) = toupper(*action_upper);
        
        //前后綴模式
        //Index_Action 或 Action_Index
        //IndexAction 或 ActionIndex
        if (YAF_G(name_suffix)) {
            class_len = spprintf(&class_name, 0, "%s%s%s", action_upper, YAF_G(name_separator), "Action");
        } else {
            class_len = spprintf(&class_name, 0, "%s%s%s", "Action", YAF_G(name_separator), action_upper);
        }
       
        //類名轉(zhuǎn)換為小寫
        class_lowercase = zend_str_tolower_dup(class_name, class_len);
        //是否存在這個(gè)Action類
        if (zend_hash_find(EG(class_table), class_lowercase, class_len + 1, (void **) &ce) == SUCCESS) {
            efree(action_upper);
            efree(class_lowercase);
            //是否繼承Yaf_Action_Abstract
            if (instanceof_function(*ce, yaf_action_ce TSRMLS_CC)) {
                efree(class_name);
                return *ce;
            } else {
                yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "Action %s must extends from %s", class_name, yaf_action_ce->name);
                efree(class_name);
                return NULL;
            }
        }
        //在數(shù)組中找到對(duì)應(yīng)的key(action名稱)
        if (zend_hash_find(Z_ARRVAL_P(actions_map), action, len + 1, (void **)&ppaction) == SUCCESS) {
            char *action_path;
            uint action_path_len;
            //把值(后面的文件路徑)賦給action_path
            //也就是得到了action類所在的文件了
            action_path_len = spprintf(&action_path, 0, "%s%c%s", app_dir, DEFAULT_SLASH, Z_STRVAL_PP(ppaction));
            //導(dǎo)入這個(gè)類文件
            if (yaf_loader_import(action_path, action_path_len, 0 TSRMLS_CC)) {
                //action類是否存在
                if (zend_hash_find(EG(class_table), class_lowercase, class_len + 1, (void **) &ce) == SUCCESS) {
                    efree(action_path);
                    efree(action_upper);
                    efree(class_lowercase);
                    //是否繼承Yaf_Action_Abstract
                    if (instanceof_function(*ce, yaf_action_ce TSRMLS_CC)) {
                        efree(class_name);
                        //返回Action類指針
                        return *ce;
                    } else {
                        yaf_trigger_error(YAF_ERR_TYPE_ERROR TSRMLS_CC, "Action %s must extends from %s", class_name, yaf_action_ce->name);
                        efree(class_name);
                    }

                } else {
                    yaf_trigger_error(YAF_ERR_NOTFOUND_ACTION TSRMLS_CC, "Could not find action %s in %s", class_name, action_path);
                }

                efree(action_path);
                efree(action_upper);
                efree(class_name);
                efree(class_lowercase);

            } else {
                yaf_trigger_error(YAF_ERR_NOTFOUND_ACTION TSRMLS_CC, "Failed opening action script %s: %s", action_path, strerror(errno));
                efree(action_path);
            }
        } else {
            yaf_trigger_error(YAF_ERR_NOTFOUND_ACTION TSRMLS_CC, "There is no method %s%s in %s::$%s",
                    action, "Action", Z_OBJCE_P(controller)->name, YAF_CONTROLLER_PROPERTY_NAME_ACTIONS);
        } 
     } else if (YAF_G(st_compatible)) {
            //省略.....

            //這部分不說了阳液,大概就是在 actions 里面沒有找到這個(gè)action的路徑
            //那么就嘗試自己拼接路徑去加載

            if (def_module) {
                spprintf(&directory, 0, "%s%c%s", app_dir, DEFAULT_SLASH, "actions");
            } else {
                spprintf(&directory, 0, "%s%c%s%c%s%c%s", app_dir, DEFAULT_SLASH,
                    "modules", DEFAULT_SLASH, module, DEFAULT_SLASH, "actions");
            }

           //省略.....
     }
}

上面也看到action的路徑是按照你所填寫的映射中地址加載怕敬,但是類名卻是action的名稱拼接的,所以雖然類文件不需要按照Yaf的標(biāo)準(zhǔn)路徑設(shè)定帘皿,但是類名必須和action一致东跪,在這個(gè)環(huán)節(jié)可能會(huì)因?yàn)閍ction的特殊性出現(xiàn)找不到類的問題.

Yaf 自動(dòng)加載

在實(shí)例化 application 類的時(shí)候,內(nèi)部會(huì)自動(dòng)實(shí)例化一個(gè) Yaf_Loader 對(duì)象鹰溜,同時(shí)往內(nèi)核注冊(cè)了一個(gè)自動(dòng)加載器 autoload 這里注冊(cè)自動(dòng)加載器也是用內(nèi)核提供的 spl_autoload_register

yaf_loader_register() 注冊(cè)自動(dòng)加載器

int yaf_loader_register(yaf_loader_t *loader TSRMLS_DC) {
    zval *autoload, *method, *function, *ret = NULL;
    zval **params[1] = {&autoload};
     
    //設(shè)置autoload為一個(gè)數(shù)組
    MAKE_STD_ZVAL(autoload);
    array_init(autoload);

#define YAF_AUTOLOAD_FUNC_NAME  "autoload"
#define YAF_SPL_AUTOLOAD_REGISTER_NAME "spl_autoload_register"

    //設(shè)置method = autoload
    MAKE_STD_ZVAL(method);
    ZVAL_STRING(method, YAF_AUTOLOAD_FUNC_NAME, 1);

    //把loader對(duì)象添加到autoload數(shù)組里面
    zend_hash_next_index_insert(Z_ARRVAL_P(autoload), &loader, sizeof(yaf_loader_t *), NULL);
    //把method添加到autoload數(shù)組里面
    zend_hash_next_index_insert(Z_ARRVAL_P(autoload), &method, sizeof(zval *), NULL);

    //設(shè)置function =  spl_autoload_register
    MAKE_STD_ZVAL(function);
    ZVAL_STRING(function, YAF_SPL_AUTOLOAD_REGISTER_NAME, 0);
    
    //這里注冊(cè)自動(dòng)加載器跟php中調(diào)用spl_autoload_register形式幾乎差不多
    //spl_autoload_register(array(loader,autoload))
   
    do {
        zend_fcall_info fci = {
            sizeof(fci),
            EG(function_table),
            function,
            NULL,
            &ret,
            1,
            (zval ***)params,
            NULL,
            1
        };
        // 調(diào)用 spl_autoload_register 注冊(cè)
        if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
            if (ret) {
                zval_ptr_dtor(&ret);
            }
            efree(function);
            zval_ptr_dtor(&autoload);
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to register autoload function %s", YAF_AUTOLOAD_FUNC_NAME);
            return 0;
        }
        if (ret) {
            zval_ptr_dtor(&ret);
        }
        efree(function);
        zval_ptr_dtor(&autoload);
    } while (0);
    return 1;
}

PHP_METHOD(yaf_loader, autoload) 自動(dòng)加載器

PHP_METHOD(yaf_loader, autoload) {
    char *class_name, *origin_classname, *app_directory, *directory = NULL, *file_name = NULL;
#ifdef YAF_HAVE_NAMESPACE
    char *origin_lcname = NULL;
#endif
    uint separator_len, class_name_len, file_name_len = 0;
    
    //獲取類名
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &class_name, &class_name_len) == FAILURE) {
        return;
    }
    //分隔符長(zhǎng)度
    separator_len = YAF_G(name_separator_len);
    //根目錄
    app_directory = YAF_G(directory);
    origin_classname = class_name;

    do {
        if (!class_name_len) {
            break;
        }
//命名空間處理方式
#ifdef YAF_HAVE_NAMESPACE
        {
            int pos = 0;
            origin_lcname = estrndup(class_name, class_name_len);
            class_name    = origin_lcname;
            while (pos < class_name_len) {
                if (*(class_name + pos) == '\\') {
                    *(class_name + pos) = '_';
                }
                pos += 1;
            }
        }
#endif
#define YAF_LOADER_RESERVERD                "Yaf_"
        //不允許類名Yaf打頭
        if (strncmp(class_name, YAF_LOADER_RESERVERD, YAF_LOADER_LEN_RESERVERD) == 0) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "You should not use '%s' as class name prefix", YAF_LOADER_RESERVERD);
        }
#define YAF_LOADER_MODEL                    "Model"
        //是否屬于Model類
        if (yaf_loader_is_category(class_name, class_name_len, YAF_LOADER_MODEL, YAF_LOADER_LEN_MODEL TSRMLS_CC)) {
#define YAF_MODEL_DIRECTORY_NAME            "models"
            //獲取類文件的路徑
            //app_directory/models
            spprintf(&directory, 0, "%s/%s", app_directory, YAF_MODEL_DIRECTORY_NAME);
            //獲取文件名字的長(zhǎng)度虽填,減去分隔符和后綴Index_Model
            file_name_len = class_name_len - separator_len - YAF_LOADER_LEN_MODEL;
           //是否配置后綴式
            if (YAF_G(name_suffix)) {
                //獲取文件名字
                file_name = estrndup(class_name, file_name_len);
            } else {
                //獲取文件名字
                file_name = estrdup(class_name + YAF_LOADER_LEN_MODEL + separator_len);
            }

            break;
        }
#define YAF_LOADER_PLUGIN                   "Plugin"
        //是否屬于plugin類,流程跟上面一樣
        if (yaf_loader_is_category(class_name, class_name_len, YAF_LOADER_PLUGIN, YAF_LOADER_LEN_PLUGIN TSRMLS_CC)) {
            //獲取類文件的路徑
            //app_directory/plugins
            spprintf(&directory, 0, "%s/%s", app_directory, YAF_PLUGIN_DIRECTORY_NAME);
            file_name_len = class_name_len - separator_len - YAF_LOADER_LEN_PLUGIN;

            if (YAF_G(name_suffix)) {
                file_name = estrndup(class_name, file_name_len);
            } else {
                file_name = estrdup(class_name + YAF_LOADER_LEN_PLUGIN + separator_len);
            }

            break;
        }
#define YAF_LOADER_CONTROLLER               "Controller"
        //是否屬于Controller類曹动,流程跟上面一樣
        if (yaf_loader_is_category(class_name, class_name_len, YAF_LOADER_CONTROLLER, YAF_LOADER_LEN_CONTROLLER TSRMLS_CC)) {
            //獲取類文件的路徑
            //app_directory/controllers
            //可以看到這里只能獲取Controllers目錄下的控制器
            //不能獲取models/model/controllers/這種形式
            spprintf(&directory, 0, "%s/%s", app_directory, YAF_CONTROLLER_DIRECTORY_NAME);
            file_name_len = class_name_len - separator_len - YAF_LOADER_LEN_CONTROLLER;

            if (YAF_G(name_suffix)) {
                file_name = estrndup(class_name, file_name_len);
            } else {
                file_name = estrdup(class_name + YAF_LOADER_LEN_CONTROLLER + separator_len);
            }

            break;
        }


/* {{{ This only effects internally */
        if (YAF_G(st_compatible) && (strncmp(class_name, YAF_LOADER_DAO, YAF_LOADER_LEN_DAO) == 0
                    || strncmp(class_name, YAF_LOADER_SERVICE, YAF_LOADER_LEN_SERVICE) == 0)) {
            /* this is a model class */
            spprintf(&directory, 0, "%s/%s", app_directory, YAF_MODEL_DIRECTORY_NAME);
        }
/* }}} */

        file_name_len = class_name_len;
        file_name     = class_name;

    } while(0);

    if (!app_directory && directory) {
        efree(directory);
#ifdef YAF_HAVE_NAMESPACE
        if (origin_lcname) {
            efree(origin_lcname);
        }
#endif
        if (file_name != class_name) {
            efree(file_name);
        }

        php_error_docref(NULL TSRMLS_CC, E_WARNING,
                "Couldn't load a framework MVC class without an %s initializing", yaf_application_ce->name);
        RETURN_FALSE;
    }

    if (!YAF_G(use_spl_autoload)) {
        //加載這個(gè)類
        if (yaf_internal_autoload(file_name, file_name_len, &directory TSRMLS_CC)) {
            //把類名轉(zhuǎn)成小寫
            char *lc_classname = zend_str_tolower_dup(origin_classname, class_name_len);
            //是否存在這個(gè)類斋日,如果存在則代表加載成功
            if (zend_hash_exists(EG(class_table), lc_classname, class_name_len + 1)) {
#ifdef YAF_HAVE_NAMESPACE
                if (origin_lcname) {
                    efree(origin_lcname);
                }
#endif
                if (directory) {
                    efree(directory);
                }

                if (file_name != class_name) {
                    efree(file_name);
                }

                efree(lc_classname);
                //返回成功
                RETURN_TRUE;
            } else {
                efree(lc_classname);
                php_error_docref(NULL TSRMLS_CC, E_STRICT, "Could not find class %s in %s", class_name, directory);
            }
        }  else {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed opening script %s: %s", directory, strerror(errno));
        }

#ifdef YAF_HAVE_NAMESPACE
        if (origin_lcname) {
            efree(origin_lcname);
        }
#endif
        if (directory) {
            efree(directory);
        }
        if (file_name != class_name) {
            efree(file_name);
        }
        RETURN_TRUE;
    } else {
        //跟上面流程差不多
        char *lower_case_name = zend_str_tolower_dup(origin_classname, class_name_len);
        if (yaf_internal_autoload(file_name, file_name_len, &directory TSRMLS_CC) &&
                zend_hash_exists(EG(class_table), lower_case_name, class_name_len + 1)) {
#ifdef YAF_HAVE_NAMESPACE
            if (origin_lcname) {
                efree(origin_lcname);
            }
#endif
            if (directory) {
                efree(directory);
            }
            if (file_name != class_name) {
                efree(file_name);
            }

            efree(lower_case_name);
            RETURN_TRUE;
        }
#ifdef YAF_HAVE_NAMESPACE
        if (origin_lcname) {
            efree(origin_lcname);
        }
#endif
        if (directory) {
            efree(directory);
        }
        if (file_name != class_name) {
            efree(file_name);
        }
        efree(lower_case_name);
        RETURN_FALSE;
    }
}

yaf_internal_autoload() 加載類文件

int yaf_internal_autoload(char *file_name, uint name_len, char **directory TSRMLS_DC) {
    zval *library_dir, *global_dir;
    char *q, *p, *seg;
    uint seg_len, directory_len, status;
    char *ext = YAF_G(ext);
    smart_str buf = {0};
    //判斷傳遞的路徑是否為空
    //如果為空則代表要加載的類文件不屬于yaf框架規(guī)定的目錄
    //有可能是公共庫(kù)文件目錄
    if (NULL == *directory) {
        char *library_path;
        uint  library_path_len;
        yaf_loader_t *loader;

        loader = yaf_loader_instance(NULL, NULL, NULL TSRMLS_CC);

        if (!loader) {
            /* since only call from userspace can cause loader is NULL, exception throw will works well */
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s need to be initialize first", yaf_loader_ce->name);
            return 0;
        } else {
            //獲取本地類庫(kù)地址
            library_dir = zend_read_property(yaf_loader_ce, loader, ZEND_STRL(YAF_LOADER_PROPERTY_NAME_LIBRARY), 1 TSRMLS_CC);
            //獲取全局類庫(kù)地址
            global_dir  = zend_read_property(yaf_loader_ce, loader, ZEND_STRL(YAF_LOADER_PROPERTY_NAME_GLOBAL_LIB), 1 TSRMLS_CC);
            //判斷類名前綴是否已經(jīng)注冊(cè)過,如果已經(jīng)注冊(cè)過則在本地類庫(kù)去找
            //就是調(diào)用 Yaf_Loader::registerLocalNamespace() 注冊(cè)
            //如果不注冊(cè)的話全部去公共類庫(kù)下尋找
            if (yaf_loader_is_local_namespace(loader, file_name, name_len TSRMLS_CC)) {
                library_path = Z_STRVAL_P(library_dir);
                library_path_len = Z_STRLEN_P(library_dir);
            } else {
                library_path = Z_STRVAL_P(global_dir);
                library_path_len = Z_STRLEN_P(global_dir);
            }
        }

        if (NULL == library_path) {
            php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s requires %s(which set the library_directory) to be initialized first", yaf_loader_ce->name, yaf_application_ce->name);
            return 0;
        }

        smart_str_appendl(&buf, library_path, library_path_len);
    } else {
        smart_str_appendl(&buf, *directory, strlen(*directory));
        efree(*directory);
    }

    directory_len = buf.len;

    /* aussume all the path is not end in slash */
    smart_str_appendc(&buf, DEFAULT_SLASH);
    
    //如果這個(gè)文件名或者類名是這種形式的Service_Http_Post
    //下面這段代碼就會(huì)把這個(gè)類名切分成路徑
    //directory/Service/Http/Post.php 這樣

    p = file_name;
    q = p;

    while (1) {
        while(++q && *q != '_' && *q != '\0');

        if (*q != '\0') {
            seg_len = q - p;
            seg     = estrndup(p, seg_len);
            smart_str_appendl(&buf, seg, seg_len);
            efree(seg);
            smart_str_appendc(&buf, DEFAULT_SLASH);
            p       = q + 1;
        } else {
            break;
        }
    }

    if (YAF_G(lowcase_path)) {
        /* all path of library is lowercase */
        zend_str_tolower(buf.c + directory_len, buf.len - directory_len);
    }

    smart_str_appendl(&buf, p, strlen(p));
    smart_str_appendc(&buf, '.');
    smart_str_appendl(&buf, ext, strlen(ext));

    smart_str_0(&buf);

    if (directory) {
        *(directory) = estrndup(buf.c, buf.len);
    }
    //這里最后把類文件導(dǎo)入并調(diào)用內(nèi)核接口進(jìn)行編譯
    status = yaf_loader_import(buf.c, buf.len, 0 TSRMLS_CC);
    smart_str_free(&buf);

    if (!status)
        return 0;

    return 1;
}

結(jié)束

上面介紹的大致就是 Yaf 框架一個(gè)運(yùn)行流程墓陈,并且把框架的主要代碼都分析了一遍恶守,可以以此作為引導(dǎo)第献,在閱讀分析源碼的時(shí)候可以邊看源碼邊對(duì)照 Yaf 框架官方文檔 或者在用Yaf框架搭建一個(gè)環(huán)境,運(yùn)行下兔港,在對(duì)照源碼分析即可庸毫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者衫樊。
  • 序言:七十年代末飒赃,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子科侈,更是在濱河造成了極大的恐慌盒揉,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兑徘,死亡現(xiàn)場(chǎng)離奇詭異刚盈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)挂脑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門藕漱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人崭闲,你說我怎么就攤上這事肋联。” “怎么了刁俭?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵橄仍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我牍戚,道長(zhǎng)侮繁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任如孝,我火速辦了婚禮宪哩,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘第晰。我一直安慰自己锁孟,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布茁瘦。 她就那樣靜靜地躺著品抽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪甜熔。 梳的紋絲不亂的頭發(fā)上圆恤,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音纺非,去河邊找鬼哑了。 笑死,一個(gè)胖子當(dāng)著我的面吹牛烧颖,可吹牛的內(nèi)容都是我干的弱左。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼炕淮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼拆火!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起涂圆,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤们镜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后润歉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體模狭,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年踩衩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嚼鹉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驱富,死狀恐怖锚赤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情褐鸥,我是刑警寧澤线脚,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站叫榕,受9級(jí)特大地震影響浑侥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晰绎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一锭吨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寒匙,春花似錦零如、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至会宪,卻和暖如春肖卧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掸鹅。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工塞帐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留拦赠,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓葵姥,卻偏偏與公主長(zhǎng)得像荷鼠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子榔幸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 快速開始 典型的目錄結(jié)構(gòu) 入口文件 所有請(qǐng)求的入口, 一般都借助于rewrite規(guī)則, 把所有的請(qǐng)求都重定向到這個(gè)...
    零一間閱讀 3,784評(píng)論 0 8
  • 如何構(gòu)建框架目錄(使用Yaf框架自帶的代碼生成工具) php-yaf-src/tools/cg/yaf_cg sa...
    ho俊閱讀 1,145評(píng)論 0 0
  • YAF框架試用 YAF框架入門教程 - http://www.reibang.com/p/1460d2296f1...
    堅(jiān)果jimbowhy閱讀 55,651評(píng)論 0 11
  • 用戶URL請(qǐng)求 調(diào)用應(yīng)用入口文件(通常是網(wǎng)站的index.php) 載入框架入口文件(ThinkPHP.php) ...
    提莫隊(duì)長(zhǎng)1234閱讀 1,860評(píng)論 0 4
  • 可以查看我做的簡(jiǎn)易流程圖允乐。 也可以看官方的標(biāo)準(zhǔn)答案。 用戶URL請(qǐng)求 調(diào)用應(yīng)用入口文件(通常是網(wǎng)站的index.p...
    蘇近之2017閱讀 784評(píng)論 0 3