介绍
Yaf框架是一个c语言编写的PHP框架,是一个以PHP扩展形式提供的PHP开发框架,相比于一般的PHP框架, 它更快,更轻便,内存占用率更低,就是本着对性能的追求,Yaf把框架中不易变的部分抽象出来,类如路由、自动加载、bootstrap、分发等,采用PHP扩展去实现,以此来保证性能。
Yaf优点
- 用c语言开发的PHP框架,相比原生的PHP,几乎不会带来额外的性能开销
- 所有的框架类,不需要编译,在PHP启动的时候加载,并常驻内存.
- 更快的执行速度,更少的内存占用.
- 灵巧的自动加载. 支持全局和局部两种加载规则, 方便类库共享.
yaf缺点
- 维护成本高,要维护PHP扩展,需要熟练C开发和Zend Api.
- 目标用户群小,现在国内很多中小型站都是使用虚拟主机,并不能随意的给PHP添加扩展.
- 不像其他框架一样提供各种丰富功能的类库和各种优雅的写法,它只提供一个MVC的基本骨架.
Yaf框架执行流程图
流程图说明
在application目录下有个Bootstrap.php文件,这个就是图中的第一个环节,如果存在Bootstrap()就会先执行该文件,该文件包含了一系列的初始化环节,并返回一个Yaf_Application对象,紧接着调用了它的run方法,run里面包含了图中所有环节,run首先是调用路由,路由的主要目的其实就是找到controllers文件,然后执行里面的init和action方法,或者找到所有actions的地址然后加载,在去执行对应的execute方法,如果设置了autoRender在返回的时候会执行render方法,就是view自动渲染,图中有六个双横线标出的环节,就是六个插件方法,用户可以自定义实现这几个方法,然后Yaf框架会在图中相应的步骤处调用对应的HOOK方法。
Yaf框架目录结构
+ public
|- index.php
|- .htaccess
|+ css
|+ img
|+ js
+ conf
|- application.ini
+ application
|+ actions
|+ index
|- Main.php
|+ controllers
|- Index.php
|+ views
|+ index
|- index.phtml
|+ modules
|+ admin
|+ controllers
|- Index.php
|+ library
|+ models
|- baseModel.php
|+ plugins
|- testPlugin.php
Bootstrap.php 引导文件
Yaf配置项说明
选项名称 |
默认值 |
说明 |
yaf.environ |
product |
环境名称, 当用INI作为Yaf的配置文件时, 这个指明了Yaf将要在INI配置中读取的节的名字 |
yaf.library |
NULL |
全局类库的目录路径 |
yaf.cache_config |
0 |
是否缓存配置文件(只针对INI配置文件生效), 打开此选项可在复杂配置的情况下提高性能 |
yaf.name_suffix |
1 |
在处理Controller, Action, Plugin, Model的时候, 类名中关键信息是否是后缀式, 比如UserModel, 而在前缀模式下则是ModelUser |
yaf.name_separator |
"" |
在处理Controller, Action, Plugin, Model的时候, 前缀和名字之间的分隔符, 默认为空, 也就是UserPlugin, 加入设置为"_", 则判断的依据就会变成:"User_Plugin", 这个主要是为了兼容ST已有的命名规范 |
yaf.forward_limit |
5 |
forward最大嵌套深度 |
yaf.use_namespace |
0 |
开启的情况下, Yaf将会使用命名空间方式注册自己的类, 比如Yaf_Application将会变成Yaf\Application |
yaf.use_spl_autoload |
0 |
开启的情况下, Yaf在加载不成功的情况下, 会继续让PHP的自动加载函数加载, 从性能考虑, 除非特殊情况, 否则保持这个选项关闭 |
[Yaf]
yaf.library = "c:/huan"
yaf.name_suffix = 0
yaf.name_separator = "_"
yaf.environ = "product"
选项名称 |
默认值 |
说明 |
application.ext |
php |
PHP脚本的扩展名 |
application.bootstrap |
Bootstrapplication.php |
Bootstrap路径(绝对路径) |
application.library |
application.directory + "/library" |
本地(自身)类库的绝对目录地址 |
application.baseUri |
NULL |
在路由中, 需要忽略的路径前缀, 一般不需要设置, Yaf会自动判断. |
application.dispatcher.defaultModule |
index |
默认的模块 |
application.dispatcher.throwException |
True |
在出错的时候, 是否抛出异常 |
application.dispatcher.catchException |
False |
是否使用默认的异常捕获Controller, 如果开启, 在有未捕获的异常的时候, 控制权会交给ErrorController的errorAction方法, 可以通过$request->getException()获得此异常对象 |
application.dispatcher.defaultController |
index |
默认的控制器 |
application.dispatcher.defaultAction |
index |
默认的动作 |
application.view.ext |
phtml |
视图模板扩展名 |
application.modules |
modules |
声明存在的模块名, 请注意, 如果你要定义这个值, 一定要定义Index Module |
[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配置文件里面除了配置框架本身的配置项,还可以添加一些我们自定义的配置项,同时支持继承配置功能,在框架启动的时候会根据yaf.environ设定的节点名字去读取.
配置文件解析完毕后读取到内存的状态
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
)
调用Yaf框架
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) {
$config = Yaf_Application::app()->getConfig();
Yaf_Registry::set("config", $config);
$dispatcher->getConfig()->get('database')->master->host
$dispatcher->autoRender(false);
$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){
$objPlugin = new Test_Plugin();
$dispatcher->registerPlugin($objPlugin);
}
public function _initRegistLocalLib(Yaf_Dispatcher $dispatcher){
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 {
public $actions = array(
'one' => 'actions/index/One.php',
'two' => 'actions/index/Two.php',
);
public function ini(){
}
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并没有实现Model层,需要自己实现或者调用现成的Model库.
扩展-核心功能模块实现
扩展 Yaf_Application 类注册
YAF_STARTUP_FUNCTION(application) {
zend_class_entry ce;
YAF_INIT_CLASS_ENTRY(ce, "Yaf_Application", "Yaf\\Application", yaf_application_methods);
yaf_application_ce = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);
yaf_application_ce->ce_flags |= ZEND_ACC_FINAL_CLASS;
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);
return SUCCESS;
}
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}
};
上面这个就是在扩展里面注册一个类的实现,Yaf其他的类文件在注册类的时候也几乎和上面方式一致,具体看下源码就可以了,下面将从实例化一个Yaf_Application类开始分析。
扩展 Yaf_Application 类构造函数 __construct 实现
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;
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
if (!ZVAL_IS_NULL(app)) {
yaf_trigger_error(YAF_ERR_STARTUP_FAILED TSRMLS_CC, "Only one application can be initialized");
RETURN_FALSE;
}
self = getThis();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|z", &config, §ion) == 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);
zconfig = yaf_config_instance(NULL, config, section TSRMLS_CC);
efree(section);
} else {
zconfig = yaf_config_instance(NULL, config, section TSRMLS_CC);
}
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 = 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;
}
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;
}
yaf_dispatcher_set_request(zdispatcher, request TSRMLS_CC);
zend_update_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_CONFIG), zconfig TSRMLS_CC);
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);
if (YAF_G(local_library)) {
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;
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;
}
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);
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);
}
zend_update_static_property(yaf_application_ce, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_APP), self TSRMLS_CC);
}
PHP_METHOD(Yaf_application, bootstrap) 扩展实现
PHP_METHOD(yaf_application, bootstrap) {
char *bootstrap_path;
uint len, retval = 1;
zend_class_entry **ce;
yaf_application_t *self = getThis();
if (zend_hash_find(EG(class_table), YAF_DEFAULT_BOOTSTRAP_LOWER, YAF_DEFAULT_BOOTSTRAP_LEN, (void **) &ce) != SUCCESS) {
if (YAF_G(bootstrap)) {
bootstrap_path = estrdup(YAF_G(bootstrap));
len = strlen(YAF_G(bootstrap));
} else {
len = spprintf(&bootstrap_path, 0, "%s%c%s.%s", YAF_G(directory), DEFAULT_SLASH, YAF_DEFAULT_BOOTSTRAP, YAF_G(ext));
}
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;
} 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;
} 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;
MAKE_STD_ZVAL(bootstrap);
object_init_ex(bootstrap, *ce);
dispatcher = zend_read_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_DISPATCHER), 1 TSRMLS_CC);
methods = &((*ce)->function_table);
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;
zend_hash_get_current_key_ex(methods, &func, &len, &idx, 0, NULL);
#define YAF_BOOTSTRAP_INITFUNC_PREFIX "_init"
if (strncasecmp(func, YAF_BOOTSTRAP_INITFUNC_PREFIX, sizeof(YAF_BOOTSTRAP_INITFUNC_PREFIX)-1)) {
continue;
}
zend_call_method(&bootstrap, *ce, NULL, func, len - 1, NULL, 1, dispatcher, NULL TSRMLS_CC);
if (EG(exception)) {
zval_ptr_dtor(&bootstrap);
RETURN_FALSE;
}
}
zval_ptr_dtor(&bootstrap);
}
RETVAL_ZVAL(self, 1, 0);
}
PHP_METHOD(yaf_application, run) 扩展实现
PHP_METHOD(yaf_application, run) {
zval *running;
yaf_dispatcher_t *dispatcher;
yaf_response_t *response;
yaf_application_t *self = getThis();
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;
}
ZVAL_BOOL(running, 1);
zend_update_property(yaf_application_ce, self, ZEND_STRL(YAF_APPLICATION_PROPERTY_NAME_RUN), running TSRMLS_CC);
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;
}
yaf_dispatcher_dispatch() 方法里面主要分两部分,路由+分发,其中夹杂着一些插件调用,就是上图中双横线标出的环节,先看下官方对插件的说明。
触发顺序 |
名称 |
触发时机 |
1 |
routerStartup |
在路由之前触发 |
2 |
routerShutdown |
路由结束之后触发 |
3 |
dispatchLoopStartup |
分发循环开始之前被触发 |
4 |
preDispatch |
分发之前触发 |
5 |
postDispatch |
分发结束之后触发 |
6 |
dispatchLoopShutdown |
分发循环结束之后触发 |
扩展中插件方法名用宏表示
#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 = yaf_response_instance(NULL, sapi_module.name TSRMLS_CC);
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)) {
YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_ROUTESTARTUP, request, response);
YAF_EXCEPTION_HANDLE(dispatcher, request, response);
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);
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);
}
YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_LOOPSTARTUP, request, response);
YAF_EXCEPTION_HANDLE(dispatcher, request, response);
view = yaf_dispatcher_init_view(dispatcher, NULL, NULL TSRMLS_CC);
if (!view) {
return NULL;
}
do {
YAF_PLUGIN_HANDLE(plugins, YAF_PLUGIN_HOOK_PREDISPATCH, request, response);
YAF_EXCEPTION_HANDLE(dispatcher, request, response);
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);
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));
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() 路由入口
int yaf_dispatcher_route(yaf_dispatcher_t *dispatcher, yaf_request_t *request TSRMLS_DC) {
zend_class_entry *router_ce;
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)) {
if ((router_ce = Z_OBJCE_P(router)) == yaf_router_ce) {
yaf_router_route(router, request TSRMLS_CC);
} else {
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;
}
这段代码是路由环节的入口,dispatcher初始化时会创建内置路由器,这里只涉及路由器概念,上面的自定义并不是自定义路由协议,而是你可以重新写一个路由器,我们通常在项目中自定义路由协议就可以了,没有必要自己实现一个路由器。而且框架中其实也是写死了内置路由器,没有给你set自定义路由器的接口。
yaf_router_route() 执行路由
int yaf_router_route(yaf_router_t *router, yaf_request_t *request TSRMLS_DC) {
zval *routers, *ret;
yaf_route_t **route;
HashTable *ht;
routers = zend_read_property(yaf_router_ce, router, ZEND_STRL(YAF_ROUTER_PROPERTY_NAME_ROUTES), 1 TSRMLS_CC);
ht = Z_ARRVAL_P(routers);
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;
}
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;
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;
}
yaf_request_set_routed(request, 1 TSRMLS_CC);
zval_ptr_dtor(&ret);
break;
}
}
return 1;
}
内置的路由协议
上面几种路由协议源代码列表
yaf_route_static.c
yaf_route_simple.c
yaf_route_supervar.c
yaf_route_rewrite.c
yaf_route_regex.c
yaf_route_map.c
无路是哪个路由协议最后功能都是为了设置module,controller,action的名称
yaf_dispatcher_handle() 开始分发
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 {
int is_def_module = 0;
zval *module, *controller, *dmodule, *instantly_flush;
zend_class_entry *ce;
yaf_controller_t *executor;
zend_function *fptr;
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);
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;
}
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);
yaf_controller_construct(ce, icontroller, request, response, view, NULL TSRMLS_CC);
if (EG(exception)) {
zval_ptr_dtor(&icontroller);
return 0;
}
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 = 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));
Z_ADDREF_P(action);
func_name_len = spprintf(&func_name, 0, "%s%s", action_lower, "action");
efree(action_lower);
if (zend_hash_find(&((ce)->function_table), func_name, func_name_len + 1, (void **)&fptr) == SUCCESS) {
executor = icontroller;
zend_call_method(&icontroller, ce, NULL, func_name, func_name_len, &ret, 0, NULL, NULL TSRMLS_CC);
efree(func_name);
} 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)) {
MAKE_STD_ZVAL(iaction);
object_init_ex(iaction, ce);
executor = iaction;
zend_call_method_with_0_params(&iaction, ce, NULL, "execute", &ret);
} else {
efree(func_name);
zval_ptr_dtor(&icontroller);
return 0;
}
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;
}
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;
if (def_module) {
directory_len = spprintf(&directory, 0, "%s%c%s", app_dir, DEFAULT_SLASH, YAF_CONTROLLER_DIRECTORY_NAME);
} else {
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;
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);
}
class_lowercase = zend_str_tolower_dup(class, class_len);
if (zend_hash_find(EG(class_table), class_lowercase, class_len + 1, (void **)&ce) != SUCCESS) {
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;
} 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;
} 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_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_upper) = toupper(*action_upper);
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);
}
class_lowercase = zend_str_tolower_dup(class_name, class_len);
if (zend_hash_find(EG(class_table), class_lowercase, class_len + 1, (void **) &ce) == SUCCESS) {
efree(action_upper);
efree(class_lowercase);
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;
}
}
if (zend_hash_find(Z_ARRVAL_P(actions_map), action, len + 1, (void **)&ppaction) == SUCCESS) {
char *action_path;
uint action_path_len;
action_path_len = spprintf(&action_path, 0, "%s%c%s", app_dir, DEFAULT_SLASH, Z_STRVAL_PP(ppaction));
if (yaf_loader_import(action_path, action_path_len, 0 TSRMLS_CC)) {
if (zend_hash_find(EG(class_table), class_lowercase, class_len + 1, (void **) &ce) == SUCCESS) {
efree(action_path);
efree(action_upper);
efree(class_lowercase);
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);
}
} 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)) {
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的标准路径设定,但是类名必须和action一致,在这个环节可能会因为action的特殊性出现找不到类的问题.
Yaf 自动加载
在实例化 application 类的时候,内部会自动实例化一个 Yaf_Loader 对象,同时往内核注册了一个自动加载器 autoload 这里注册自动加载器也是用内核提供的 spl_autoload_register
yaf_loader_register() 注册自动加载器
int yaf_loader_register(yaf_loader_t *loader TSRMLS_DC) {
zval *autoload, *method, *function, *ret = NULL;
zval **params[1] = {&autoload};
MAKE_STD_ZVAL(autoload);
array_init(autoload);
#define YAF_AUTOLOAD_FUNC_NAME "autoload"
#define YAF_SPL_AUTOLOAD_REGISTER_NAME "spl_autoload_register"
MAKE_STD_ZVAL(method);
ZVAL_STRING(method, YAF_AUTOLOAD_FUNC_NAME, 1);
zend_hash_next_index_insert(Z_ARRVAL_P(autoload), &loader, sizeof(yaf_loader_t *), NULL);
zend_hash_next_index_insert(Z_ARRVAL_P(autoload), &method, sizeof(zval *), NULL);
MAKE_STD_ZVAL(function);
ZVAL_STRING(function, YAF_SPL_AUTOLOAD_REGISTER_NAME, 0);
do {
zend_fcall_info fci = {
sizeof(fci),
EG(function_table),
function,
NULL,
&ret,
1,
(zval ***)params,
NULL,
1
};
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) 自动加载器
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;
}
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_"
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"
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"
spprintf(&directory, 0, "%s/%s", app_directory, YAF_MODEL_DIRECTORY_NAME);
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"
if (yaf_loader_is_category(class_name, class_name_len, YAF_LOADER_PLUGIN, YAF_LOADER_LEN_PLUGIN TSRMLS_CC)) {
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"
if (yaf_loader_is_category(class_name, class_name_len, YAF_LOADER_CONTROLLER, YAF_LOADER_LEN_CONTROLLER TSRMLS_CC)) {
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;
}
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)) {
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)) {
if (yaf_internal_autoload(file_name, file_name_len, &directory TSRMLS_CC)) {
char *lc_classname = zend_str_tolower_dup(origin_classname, class_name_len);
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};
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) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s need to be initialize first", yaf_loader_ce->name);
return 0;
} else {
library_dir = zend_read_property(yaf_loader_ce, loader, ZEND_STRL(YAF_LOADER_PROPERTY_NAME_LIBRARY), 1 TSRMLS_CC);
global_dir = zend_read_property(yaf_loader_ce, loader, ZEND_STRL(YAF_LOADER_PROPERTY_NAME_GLOBAL_LIB), 1 TSRMLS_CC);
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;
smart_str_appendc(&buf, DEFAULT_SLASH);
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)) {
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);
}
status = yaf_loader_import(buf.c, buf.len, 0 TSRMLS_CC);
smart_str_free(&buf);
if (!status)
return 0;
return 1;
}
结束
上面介绍的大致就是 Yaf 框架一个运行流程,并且把框架的主要代码都分析了一遍,可以以此作为引导,在阅读分析源码的时候可以边看源码边对照
Yaf 框架官方文档 或者在用Yaf框架搭建一个环境,运行下,在对照源码分析即可。
来源:https://www.jianshu.com/p/130389235abc
评论