首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 互联网 >

Yaf源码翻阅之请求的处理(二)

2013-11-29 
Yaf源码阅读之请求的处理(二)上一篇文章?我们分析了Yaf框架的启动,包括配置文件的初始化以及框架类的加载。

Yaf源码阅读之请求的处理(二)

上一篇文章?我们分析了Yaf框架的启动,包括配置文件的初始化以及框架类的加载。本文将分析Yaf

处理一次Web请求的详细过程,这是一个Web框架最核心的部分,理解了这点,就理解了Yaf的实现原理。

?

(一)框架类的实例化

在上一篇文章提到了Yaf框架类的加载,类加载完成后,还要实例化,

我们逐一分析Yaf各个框架类的构造函数。

?

不急于分析各种调用关系,我们先看下Application启动后,Yaf的对象关系如图1-1所示。

Yaf源码翻阅之请求的处理(二)
???

?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?图1-1 Yaf对象关系图

?

一切构造从?new?Yaf_Application() 开始。

?

所有类的实例化都从Yaf_Applicaion的构造函数开始,它主要做了这几件事:

实例化Config实例化Request实例化Dispatcher实例化Loader

yaf_application.c

PHP_METHOD(yaf_application, __construct) {//实例化Config,用于读取配置信息zconfig = yaf_config_instance(NULL, config, section TSRMLS_CC);//解析application的配置信息,将配置参数保存到全局变量中yaf_application_parse_option(zend_read_property(yaf_config_ce,   zconfig,    ZEND_STRL(YAF_CONFIG_PROPERT_NAME),1 TSRMLS_CC) TSRMLS_CC)//实例化Request,保存请求的信息request = yaf_request_instance(NULL, YAF_G(base_uri) TSRMLS_CC);//实例化分发器Dispatcher,这是Yaf的核心控制类zdispatcher = yaf_dispatcher_instance(NULL TSRMLS_CC);yaf_dispatcher_set_request(zdispatcher, request TSRMLS_CC);//把config实例设置成Application的属性zend_update_property(yaf_application_ce, self,  ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_CONFIG),  zconfig TSRMLS_CC);//把request实例设置成Application的属性zend_update_property(yaf_application_ce, self,  ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER),  zdispatcher TSRMLS_CC);//创建loader,用于自动加载类loader = yaf_loader_instance(NULL, local_library,strlen(YAF_G(global_library))? YAF_G(global_library) : NULL TSRMLS_CC);//把dispatcher设置成Application的属性zend_update_property(yaf_application_ce, self,  ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER),  zdispatcher TSRMLS_CC);}

?

在Yaf_Application的构造函数中,调用其他类的构造函数时,又会继续创建它依赖的其它对象,

最终所有框架类都完成实例化,形成图1-1所示的关系图,然后就可以开始处理用户的请求了。

?

(二)处理请求

几乎所有MVC的Web框架处理一个请求都会走过3个流程,如图2-1所示。

Yaf源码翻阅之请求的处理(二)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 图2-1 MVC框架处理请求的流程图

?

Yaf也是按照这个流程来处理请求的,更细化一点,Yaf提供了完善的API,

并支持Bootstrap和插件机制,我们引用Yaf官方文档的流程图来分析,如图2-2所示。


Yaf源码翻阅之请求的处理(二)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 图2-2 Yaf流程图

?

从Yaf的流程图可以看到,一切请求的处理从 run() 方法开始。

yaf_application.c

PHP_METHOD(yaf_application, run) {zval *running;yaf_dispatcher_t  *dispatcher;yaf_response_t  *response;yaf_application_t *self = getThis();//确保application的状态是非running的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;}//把application的状态置为runningZVAL_BOOL(running, 1);zend_update_property(yaf_application_ce,  self,  ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_RUN), running TSRMLS_CC);//调用dispatcher来处理这次请求dispatcher = zend_read_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER), 1 TSRMLS_CC);if ((response = yaf_dispatcher_dispatch(dispatcher TSRMLS_CC))) {RETURN_ZVAL(response, 1, 1);}RETURN_FALSE;}

?

可以看出,run() 函数调用了?yaf_dispatcher_dispatch 来处理请求。继续探索,等等,先剧透下,

我们来看看接下来的函数调用关系图,如图2-3所示。

Yaf源码翻阅之请求的处理(二)
?
?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 图2-3 处理请求的函数调用关系图

?

继续分析yaf_dispatcher_dispatch,它是处理请求的中心函数,它调用路由器完成路由,

然后根据路由结果,找到对应的action执行,最后把结果发送给客户端。

yaf_dispatcher.c

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,用来返回的数据response = yaf_response_instance(NULL, sapi_module.name TSRMLS_CC);//取得request对象request = zend_read_property(yaf_dispatcher_ce,   dispatcher,   ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_REQUEST),   1 TSRMLS_CC);//取得所有插件plugins = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_PLUGINS), 1 TSRMLS_CC);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;}//路由此次请求if (!yaf_request_is_routed(request TSRMLS_CC)) {//在路由开始前,调用各个插件的route_startup方法YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_ROUTESTARTUP, request, response);YAF_EXCEPTION_HANDLE(dispatcher, request, response);//开始路由,路由的结果是找到处理此次请求的module、controller和action//这几个结果分别保存在Request对象的$module、$controller和$action变量中if (!yaf_dispatcher_route(dispatcher, request TSRMLS_CC)) {yaf_trigger_error(YAF_ERR_ROUTE_FAILED TSRMLS_CC, "Routing request failed");YAF_EXCEPTION_HANDLE_NORET(dispatcher, request, response);zval_ptr_dtor(&response);return NULL;}yaf_dispatcher_fix_default(dispatcher, request TSRMLS_CC);//在路由完成后,调用各个插件的route_shutdown方法YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_ROUTESHUTDOWN, request, response);YAF_EXCEPTION_HANDLE(dispatcher, request, response);(void)yaf_request_set_routed(request, 1 TSRMLS_CC);} else {yaf_dispatcher_fix_default(dispatcher, request TSRMLS_CC);}//在路由结束后,分发循环之前调用各个插件的loop_startup函数YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_LOOPSTARTUP, request, response);YAF_EXCEPTION_HANDLE(dispatcher, request, response);//初始化viewview = yaf_dispatcher_init_view(dispatcher, NULL, NULL TSRMLS_CC);if (!view) {return NULL;}//进入分发循环,最多循环 application.forward_limit 次do {//在请求分发之前执行各个插件的pre_dispatch方法YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_PREDISPATCH, request, response);//调用yaf_dispatcher_handle处理请求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);//在请求分发结束后,执行各个插件的post_dispatch方法YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_POSTDISPATCH, request, response);YAF_EXCEPTION_HANDLE(dispatcher, request, response);} while (--nesting > 0 && !yaf_request_is_dispatched(request TSRMLS_CC));//在分发循环结束后,执行各个插件的loop_shutdown方法YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_LOOPSHUTDOWN, request, response);YAF_EXCEPTION_HANDLE(dispatcher, request, response);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;}//取出返回给客户端的数据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,这里不分析路由的详细过程,只需了解,路由的目的是找出

处理此次请求的module、controller和action,并把这些信息保存在Request对象中。接下来,由

yaf_dispatcher_handle函数去调用action的方法来处理请求。我们继续分析?yaf_dispatcher_handle。

yaf_dispatcher.c

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);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 {intis_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;//从Request对象中读取路由结果(module、controller)module= zend_read_property(request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_MODULE), 1 TSRMLS_CC);controller= zend_read_property(request_ce, request, ZEND_STRL(YAF_REQUEST_PROPERTY_NAME_CONTROLLER), 1 TSRMLS_CC);dmodule= zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_MODULE), 1 TSRMLS_CC);dcontroller = zend_read_property(yaf_dispatcher_ce, dispatcher, ZEND_STRL(YAF_DISPATCHER_PROPERTY_NAME_CONTROLLER), 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;} 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;}if(strncasecmp(Z_STRVAL_P(dmodule), Z_STRVAL_P(module), Z_STRLEN_P(module)) == 0) {is_def_module = 1;}/* if (strncasecmp(Z_STRVAL_P(dcontroller), Z_STRVAL_P(controller), Z_STRLEN_P(controller)) == 0) {is_def_ctr = 1;} *///实例化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;MAKE_STD_ZVAL(icontroller);object_init_ex(icontroller, ce);/* cause controller's constructor is a final method, so it must be a internal function   do {   zend_function *constructor = NULL;   constructor = Z_OBJ_HT_P(exec_ctr)->get_constructor(exec_ctr TSRMLS_CC);   if (constructor != NULL) {   if (zend_call_method_with_2_params(&exec_ctr, *ce   , &constructor, NULL, &ret, request, response) == NULL) {   yaf_trigger_error(YAF_ERR_CALL_FAILED, "function call for %s::__construct failed", (*ce)->name);   return 0;   }   }   } while(0);   */yaf_controller_construct(ce, icontroller, request, response, view, NULL TSRMLS_CC);if (EG(exception)) {zval_ptr_dtor(&icontroller);return 0;}/* view template directory for application, please notice that view engine's directory has high priority */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);//从Request对象中读取路由结果(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));php_printf("dispatcher action_lower = %s\n", action_lower);/* because the action might call the forward to override the old action */Z_ADDREF_P(action);func_name_len = spprintf(&func_name,  0, "%s%s", action_lower, "action");efree(action_lower);php_printf("dispatcher func_name = %s\n", func_name);if (zend_hash_find(&((ce)->function_table), func_name, func_name_len + 1, (void **)&fptr) == SUCCESS) {//Action是一个定义在Controller类中的成员方法,//就直接调用Controller定义的action方法uint count = 0;zval ***call_args = NULL;ret = NULL;executor = icontroller;if (fptr->common.num_args) {zval *method_name;yaf_dispatcher_get_call_parameters(request_ce, request, fptr, &call_args, &count TSRMLS_CC);MAKE_STD_ZVAL(method_name);ZVAL_STRINGL(method_name, func_name, func_name_len, 0);call_user_function_ex(&(ce)->function_table, &icontroller, method_name, &ret, count, call_args, 1, NULL TSRMLS_CC);efree(method_name);efree(call_args);} else {zend_call_method(&icontroller, ce, NULL, func_name, func_name_len, &ret, 0, NULL, NULL TSRMLS_CC);}efree(func_name);if (!ret) {zval_ptr_dtor(&action);zval_ptr_dtor(&icontroller);return 0;}if ((Z_TYPE_P(ret) == IS_BOOL&& !Z_BVAL_P(ret))) {/* no auto-render */zval_ptr_dtor(&ret);zval_ptr_dtor(&action);zval_ptr_dtor(&icontroller);return 1;}zval_ptr_dtor(&ret);} 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)) {//Action是一个独立的类,就实例化这个类,调用其execute方法zval ***call_args;yaf_action_t *iaction;uint count = 0;efree(func_name);MAKE_STD_ZVAL(iaction);object_init_ex(iaction, ce);yaf_controller_construct(ce, iaction, request, response, view, NULL TSRMLS_CC);executor = iaction;zend_update_property(ce, iaction, ZEND_STRL(YAF_CONTROLLER_PROPERTY_NAME_NAME), controller TSRMLS_CC);zend_update_property(ce, iaction, ZEND_STRL(YAF_ACTION_PROPERTY_NAME_CTRL), icontroller TSRMLS_CC);zval_ptr_dtor(&icontroller);if (fptr->common.num_args) {zval *method_name = NULL;yaf_dispatcher_get_call_parameters(request_ce, request, fptr, &call_args, &count TSRMLS_CC);MAKE_STD_ZVAL(method_name);ZVAL_STRINGL(method_name, YAF_ACTION_EXECUTOR_NAME, sizeof(YAF_ACTION_EXECUTOR_NAME) - 1, 0);call_user_function_ex(&(ce)->function_table, &iaction, method_name, &ret, count, call_args, 1, NULL TSRMLS_CC);efree(method_name);efree(call_args);} else {zend_call_method_with_0_params(&iaction, ce, NULL, "execute", &ret);}if (!ret) {zval_ptr_dtor(&action);zval_ptr_dtor(&iaction);return 0;}if (( Z_TYPE_P(ret) == IS_BOOL&& !Z_BVAL_P(ret))) {/* no auto-render */zval_ptr_dtor(&ret);zval_ptr_dtor(&action);zval_ptr_dtor(&iaction);return 1;}zval_ptr_dtor(&ret);} else {efree(func_name);zval_ptr_dtor(&icontroller);return 0;}if (executor) {/* controller's property can override the Dispatcher's */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;}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_handle函数首先从Request对象读取路由结果

(module、controller和action)

然后实创建controller对象,执行action定义的逻辑处理请求。需要注意的是,

Yaf编写Action有两种方式:

(1)把action方法写在Controller类中

?

class Controller_Index extends Yaf_Controller_Abstract {    public function indexAction () {        echo "Hello, World!";    }}

?

(2)在Controller对象的$actions保存所有action序对,序对的键必须与路由结果的action名字一样,

? ? ? ? ?而且是小写,序对的值是action类文件的相对路径,然后在action类的execute方法中写处理逻辑。

?

? ? controllers/Index.php

class Controller_Index extends Yaf_Controller_Abstract {    public $actions = array (        'index' => 'actions/Index.php',    );}

? ?actions/Index.php

class Action_Index extends Yaf_Action_Abstract {    public function execute () {        echo "Hello, World!";    }}

?

从源码中可以看出,Yaf优先从Controller中寻找action方法,如果找到,就执行之,

没有找到再从Controller中定义的$actions数组中寻找Action类,实例化这个Action类,

并执行其execute方法。

?

至此,Yaf的请求处理分析差不多了,下一篇文章将会分析Yaf的路由机制。

?

热点排行