(一)Yaf是什么php
Yaf,全称 Yet Another Framework,是一个C语言编写的、基于PHP扩展开发的PHP框架,html
相比于通常的PHP框架,它更快,快到被誉为最快的PHP开发框架。前端
它提供了Bootstrap、路由、分发、视图、插件功能。web
Yaf由惠新宸(传说中的鸟哥)开发,隆重介绍下,惠新宸,PHP开发组核心成员,数据库
PECL开发者, Zend公司外聘顾问, 曾供职于雅虎,百度,现为新浪微博架构师兼首席PHP技术顾问,是PHP5.4, 5.5的主要开发者。做为PECL开发者贡献了Yaf (Yet another framework),Yar(Yet another RPC framework)以及Yac(Yet another Cache)、Taint等多个优秀开源做品,同时也是APC,Opcache,Msgpackbootstrap
等项目的维护者...此处略去1000字。总之是一位牛得掉渣的人,Yaf在百度和新浪微博获得普遍使用。后端
在百度,绝大部分产品都是PHP开发的,其中绝大部分PHP程序都使用了Yaf框架;在新浪微博,Yaf也获得了普遍使用。这些公司的产品都是高并发、超大流量的,Yaf经受住了考验。缓存
(二)Yaf的优势安全
- 用C语言开发的PHP框架,相比原生的PHP, 几乎不会带来额外的性能开销。
- 全部的框架类,不须要编译,在PHP启动的时候加载, 并常驻内存。
- 更短的内存周转周期,提升内存利用率,下降内存占用率。
- 灵巧的自动加载。支持全局和局部两种加载规则,方便类库共享。
- 高度灵活可扩展的框架,支持自定义视图引擎,支持插件,支持自定义路由等等。
- 内建多种路由,能够兼容目前常见的各类路由协议。
- 强大而又高度灵活的配置文件支持。并支持缓存配置文件,避免复杂的配置结构带来的性能损失。
- 在框架自己,对危险的操做习惯作了禁止。
- 更快的执行速度, 更少的内存占用。
以上内容引用鸟哥的官方介绍,固然,Yaf不是一个Full-Stack的web框架,它没有对数据库操做session
的封装,更不用说ORM;它不提供表单生成、验证、分页、国际化、JS和CSS压缩等跟前端耦合
得比较紧密的功能;它不提供过滤器、缓存、组件这些web框架中经常使用的功能。不少人认为这是
Yaf的不足,但我认为这又是Yaf的优势,这表明着一种精神,就是追求简单,追求高效,追求”简单可依赖“, 因此Yaf专一于实现最核心的功能,提供最稳定的实现。Yaf不提供上面这些功能是有道理的,不提供ORM,
是由于PHP已经提供了对DB的一个轻度封装的PDO, 直接使用PDO, 会更加简单, 更加高效。不提供和
前端有关的功能,是由于在互联网产品,前端和PHP后端每每分离得很清楚,PHP只专一于组装数据给前端模板用,至于网页的布局、分页、表单的验证、JS和CSS的压缩等,交给更加专业的前端工程师解决更合适。尽管Yaf的功能有限,但Yaf是可扩展的!它提供的插件机制,能够和其它类库整合在一块儿。
总之Yaf很是适合互联网产品的开发。好比整合Smarty模板引擎,甚至能够根据产品的业务特色,基于Yaf
再扩展一套适合本身的业务层框架。总之Yaf很是适合互联网产品的开发。
(三)为何要阅读Yaf的源代码
Yaf最大的不足在于缺乏文档,别担忧,Yaf的源代码就是最好的文档,Yaf的核心代码才几千行,
可读性很强,经过阅读代码,你能够:
- 学会如何作PHP扩展开发
- 学会如何实现一个WEB框架
- 理解Yaf的内部实现,更有助于开发应用
何乐而不为,一块儿来读代码吧!
(四)Yaf的启动
Yaf的启动包括配置的初始化和框架类的加载,Yaf是一个PHP扩展,理解Yaf得先理解PHP扩展的原理,
咱们先从PHP程序的生命周期提及。
4.1 PHP程序的生命周期
一个PHP程序,依次通过Module init、Request init、Request shutdown、Module shutdown四个过程,
固然,之间还会执行脚本自身的代码。在命令行模式下运行一个PHP程序的主要流程如图4-1所示:
图4-1 PHP生命周期
实现PHP扩展,便是在以上4个阶段定义4个相应地函数,供PHP在执行的时候调用。
(1)Module init阶段的函数
- PHP_MINIT_FUNCTION(myext)
- {
- //注册常量或者类等初始化操做
- return SUCCESS;
- }
这个函数在扩展被载入时调用。
(2)Request test.php
请求test.php文件。当请求到达后,PHP会初始化执行脚本的基本环境,包括保存PHP运行过程当中变量名称
和变量值内容的符号表,以及当前全部的函数以及类等信息的符号表。
(3)Request init阶段的函数
- PHP_RINIT_FUNCTION(myext)
- {
- //例如记录请求开始时间
- //随后在请求结束的时候记录结束时间
- //这样就可以记录处理请求所花费的时间了
- return SUCCESS;
- }
(4)Execute test.php
执行test.php阶段,主要是把PHP文件编译成Opcodes,而后在PHP虚拟机下执行。
(5)Request shutdown阶段的函数
- PHP_RSHUTDOWN_FUNCTION(myext)
- {
- //例如记录请求结束时间,并把
- //相应地信息写入到日志文件中
- return SUCCESS;
- }
请求处理完成后进入结束阶段,通常脚本执行到末尾或者经过调用exit()或者die()函数,PHP都将进入结束
阶段。和开始阶段对应,结束阶段也分为两个环节,一个在请求结束后(RSHUTDOWN),一个在SAPI生命周期结束时(MSHUTDOWN)。
(6)Module shutdown阶段的函数:
- PHP_MSHUTDOWN_FUNCTION(myext)
- {
- //注销一些持久化的资源
- return SUCCESS;
- }
在请求一个PHP页面时,PHP基本上是按照这个流程执行的,Yaf扩展也是围绕这个流程,插入本身的代码,
进而使Yaf框架影响到PHP的请求中。
4.2 Yaf扩展配置的初始化
扩展能够在php.ini中写本身的配置信息,或者在编译PHP时--with-config-file-scan-dir指定目录中的配置
文件好比yaf.ini中写配置信息。Yaf扩展提供的配置项如表4-1所示
选项名称 | 默认值 | 可修改范围 | 说明 |
yaf.environ | product | PHP_INI_ALL | 环境名称, 当用INI做为Yaf的配置文件时, 这个指明了Yaf将要在INI配置中读取的节的名字 |
yaf.library | NULL | PHP_INI_ALL | 全局类库的目录路径 |
yaf.cache_config | 0 | PHP_INI_SYSTEM | 是否缓存配置文件(只针对INI配置文件生效), 打开此选项可在复杂配置的状况下提升性能 |
yaf.name_suffix | 1 | PHP_INI_ALL | 在处理Controller, Action, Plugin, Model的时候, 类名中关键信息是不是后缀式, 好比UserModel, 而在前缀模式下则是ModelUser |
yaf.name_separator | "" | PHP_INI_ALL | 在处理Controller, Action, Plugin, Model的时候, 前缀和名字之间的分隔符, 默认为空, 也就是UserPlugin, 加入设置为"_", 则判断的依据就会变成:"User_Plugin", 这个主要是为了兼容ST已有的命名规范 |
yaf.forward_limit | 5 | PHP_INI_ALL | forward最大嵌套深度 |
yaf.use_namespace | 0 | PHP_INI_ALL | 开启的状况下, Yaf将会使用命名空间方式注册本身的类, 好比Yaf_Application将会变成Yaf\Application |
yaf.use_spl_autoload | 0 | PHP_INI_SYSTEM | 开启的状况下, Yaf在加载不成功的状况下, 会继续让PHP的自动加载函数加载, 从性能考虑, 除非特殊状况, 不然保持这个选项关闭 |
表4-1 Yaf的配置选项
那么Yaf是如何读取配置文件,并初始化这些参数呢?
读取配置文件以前,得定义好参数,即声明变量来保存参数的值:
- PHP_INI_BEGIN()
- STD_PHP_INI_ENTRY("yaf.library", "", PHP_INI_ALL, OnUpdateString, global_library, zend_yaf_globals, yaf_globals)
- STD_PHP_INI_BOOLEAN("yaf.action_prefer", "0", PHP_INI_ALL, OnUpdateBool, action_prefer, zend_yaf_globals, yaf_globals)
- STD_PHP_INI_BOOLEAN("yaf.lowcase_path", "0", PHP_INI_ALL, OnUpdateBool, lowcase_path, zend_yaf_globals, yaf_globals)
- STD_PHP_INI_BOOLEAN("yaf.use_spl_autoload", "0", PHP_INI_ALL, OnUpdateBool, use_spl_autoload, zend_yaf_globals, yaf_globals)
- STD_PHP_INI_ENTRY("yaf.forward_limit", "5", PHP_INI_ALL, OnUpdateLongGEZero, forward_limit, zend_yaf_globals, yaf_globals)
- STD_PHP_INI_BOOLEAN("yaf.name_suffix", "1", PHP_INI_ALL, OnUpdateBool, name_suffix, zend_yaf_globals, yaf_globals)
- PHP_INI_ENTRY("yaf.name_separator", "", PHP_INI_ALL, OnUpdateSeparator)
- STD_PHP_INI_BOOLEAN("yaf.cache_config", "0", PHP_INI_SYSTEM, OnUpdateBool, cache_config, zend_yaf_globals, yaf_globals)
- /* {{{ This only effects internally */
- STD_PHP_INI_BOOLEAN("yaf.st_compatible", "0", PHP_INI_ALL, OnUpdateBool, st_compatible, zend_yaf_globals, yaf_globals)
- /* }}} */
- STD_PHP_INI_ENTRY("yaf.environ", "product", PHP_INI_SYSTEM, OnUpdateString, environ, zend_yaf_globals, yaf_globals)
- #ifdef YAF_HAVE_NAMESPACE
- STD_PHP_INI_BOOLEAN("yaf.use_namespace", "0", PHP_INI_SYSTEM, OnUpdateBool, use_namespace, zend_yaf_globals, yaf_globals)
- #endif
- PHP_INI_END();
定义参数时,使用宏 PHP_INI_BEGIN() 来标识的开始,并用 PHP_INI_END() 表示该配置节已经结束。而后在二者之间咱们用 PHP_INI_ENTRY() 来建立具体的配置项。PHP_INI_ENTRY 这个宏里面设置的前面的两个参数,分别表明着INI设置的名称和它的默认值。第二个参数决定设置是否容许被修改,以及它能被修改的做用域。最后一个参数是一个回调函数,当INI的值被修改时候触发此回调函数。你将会在某些修改事件的地方详细的了解这个参数。最后定义好的参数结构体以下:
- static zend_ini_entry ini_entries[] = { // BEGIN 的定义
- { 0, PHP_INI_ALL, "yaf.library", sizeof("yaf.library"), NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, NULL},
- ...
- { 0, 0, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, 0, NULL } }; // END的定义
接下来在 Module init阶段读取配置文件,并把参数值填充到 init_entries 结构体中,由REGISTER_INI_ENTRIES函数完成:
- PHP_MINIT_FUNCTION(yaf)
- {
- REGISTER_INI_ENTRIES();
- ......
- }
4.3 application配置的初始化
4.3.1 application的配置选项
与yaf的全局配置不同,application的配置是针对单个应用的,配置项如表4-2所示:
名称 | 值类型 | 默认值 | 说明 |
application.directory | String | 应用的绝对目录路径 | |
application.ext | String | php | PHP脚本的扩展名 |
application.bootstrap | String | Bootstrapplication.php | Bootstrap路径(绝对路径) |
application.library | String | application.directory + "/library" | 本地(自身)类库的绝对目录地址 |
application.baseUri | String | NULL | 在路由中, 须要忽略的路径前缀, 通常不须要设置, Yaf会自动判断. |
application.dispatcher.defaultModule | String | index | 默认的模块 |
application.dispatcher.throwException | Bool | TRUE | 在出错的时候, 是否抛出异常 |
application.dispatcher.catchException | Bool | FALSE | 是否使用默认的异常捕获Controller, 若是开启, 在有未捕获的异常的时候, 控制权会交给ErrorController的errorAction方法, 能够经过$request->getException()得到此异常对象 |
application.dispatcher.defaultController | String | index | 默认的控制器 |
application.dispatcher.defaultAction | String | index | 默认的动做 |
application.view.ext | String | phtml | 视图模板扩展名 |
application.modules | String | Index | 声明存在的模块名, 请注意, 若是你要定义这个值, 必定要定义Index Module |
application.system.* | String | * | 经过这个属性, 能够修改yaf的runtime configure, 好比application.system.lowcase_path, 可是请注意只有PHP_INI_ALL的配置项才能够在这里被修改, 此选项从2.2.0开始引入 |
表4-2 application的配置选项
4.3.2 全局变量的定义
application的配置保存在Yaf的全局变量中,全局变量的定义方式为:
php_yaf.h
- ZEND_BEGIN_MODULE_GLOBALS(yaf)
- char *ext;
- char *base_uri;
- char *environ;
- char *directory;
- char *local_library;
- ...
- ZEND_END_MODULE_GLOBALS(yaf)
- typedef struct _zend_yaf_globals {
- unsigned long counter;
- } zend_yaf_globals;
- ZEND_DECLARE_MODULE_GLOBALS(yaf);