Yaf框架是一款用PHP扩展编写的php框架。其最原始版本是百度内的AP框架,由鸟哥编写并开源为Yaf。由于项目中要用到Ap框架,所以参考Ap文档和1.0.0版本源码,做了一个大致的了解。

按照、配置、目录结构等都可以参考框架文档,直接略过。以下将从一次路由分发入手,首先了解其路由过程。

一个典型的基于Ap框架的web项目入口如下,即指定配置文件位置,并调用bootstrap()和run()两个方法。

define(‘APPLICATION_PATH’, dirname(dirname(__FILE__)));
$application = new Ap_Application( APPLICATION_PATH . “/conf/app.ini”);
$application->bootstrap()->run();

__construct、bootstrap、run三个方法的流程图如下(可点击看大图)。

从__construct结构体看起,虽然调用的是__construct,但是扩展内部利用了zend static池保存了第一次初始化后的实例,所以,若发现该实例已存在,则说明重复初始化,则直接返回false。从而保证了ap_appliciation的单例。

然后根据传入的第二个参数(例子中省略了,可以是类似dev/qa/product的字符串),或者从php.ini的ap.environ配置中获取当前所需的ini配置节。利用该特性,可以做到配置文件自动识别开发、测试、预上线、生产环境等,从而可以将配置文件统一纳入版本管理,避免人工干预,提高自动化程度。

随后是一系列的初始化操作,初始config、request、dispatcher、loader,并建立dispatcher.request和application.request,application.dispatcher,application.config三个指针关系,这就对应Ap_Dispatcher::getRequest、Ap_Application::getDispatcher和Ap_Application::getConfig三个方法。

后续做完一些属性赋值之后,将实例保存在zend static池里,对应第一步的单例判断。完成__construct方法后,没有进行实际的操作,但是大部分实例化工作已完成。

后续通过bootstrap()方法的调用,完成一系列应用层初始化工作。该方法很简单,即根据app.ini中的application.Bootstrap路径配置找到该类,并依次调用其中以_init开头的public方法。在这里可以做很多全局自定义的工作,比如设置router协议(不想用默认的Ap_Router_Static的话),初始化数据库配置等。

第三步进入到run()方法。首先确保不要重复run,随后代码主体都是对ap_dispatcher_dispatch()方法的封装。

在ap_dispatcher_dispatch()方法中,首先初始化request对象、response对象、plugins数组。

随后若该request还未被路由,则调用ap_dispatcher_route方法,根据默认的Ap_Router_Static或者配置的一系列路由协议,为request的request_uri找到module、controller、action字符串。当然,在该方法前后,会触发hook,即plugins数组里的routestartup和routeshutdown方法(可能为空)。之后,也会将request的已路由标志位设置为true。这里,之所以需要判断已路由标志位,是因为该ap_dispatcher_dispatch()方法还会被Ap_Dispatcher::dispatch()方法调用,虽然帮助文档里说,一般不需要用户手工触发。

不论之前是否被路由,完成上一步后都调用ap_dispatcher_fix_default()方法处理router解析到的module、controller、action字符串,做默认赋值、大小写转换。

然后获取view引擎(默认就是html,可以更改为smarty等)。之后开始真正的分发操作,只要未达php.ini中的ap.forward_limit上限且action方法又调用Yaf_Controller_Abstract::forward()方法产生新的action,就循环通过ap_dispatcher_handler()方法调用action。当然,在循环开始和完成时,都会触发hook,即plugins数组里的LOOPSTARTUP和LOOPSHUTDOWN方法(可能为空)。在ap_dispatcher_handler()方法前后,触发plugins数组里的PREDISPATCH和POSTDISPATCH方法(可能为空)。之后检查如果依然有未处理的forward请求,但是已达php.ini中的ap.forward_limit上限,则报错退出。

到这里,大部分路由分发工作已完成了,后面就检查_return_response标示位,若设置为true,则产生响应以后, 不自动输出给客户端, 而是返回给调用者. 可以通过Ap_Dispatcher::returnResponse来切换开关状态。所以,若该值为false,则需要发送响应,并设置response对象的body体为空。否则直接返回response对象。

平心而论,这些功能也都是每个php框架实现过的,甚至浅薄如我也写过一个公司内应用的小框架完成这些路由分发的功能。那么它胜在哪里呢?想法,性能,细节。正是这些使yaf与zend、cake等框架有大不同。

TBC。

Leave a Reply