快速开始
典型的目录结构
+ public
|- index.php //入口文件
|- .htaccess //重写规则
|+ css
|+ img
|+ js
+ conf
|- application.ini //配置文件
+ application
|+ controllers
|- Index.php //默认控制器
|+ views
|+ index //控制器
|- index.phtml //默认视图
|+ modules //其他模块
|+ library //本地类库
|+ models //model目录
|+ plugins //插件目录
入口文件
所有请求的入口, 一般都借助于rewrite规则, 把所有的请求都重定向到这个入口文件.
经典的入口文件public/index.php
<?php
define("APP_PATH", realpath(dirname(__FILE__) . '/../')); /* 指向public的上一级 */
$app = new Yaf_Application(APP_PATH . "/conf/application.ini");
$app->run();
重写规则
Apache的Rewrite (httpd.conf)
#.htaccess, 当然也可以写在httpd.conf
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php
Nginx的Rewrite (nginx.conf)
server {
listen ****;
server_name domain.com;
root document_root;
index index.php index.html index.htm;
if (!-e $request_filename) {
rewrite ^/(.*) /index.php/$1 last;
}
}
配置文件
- 配置文件支持继承, 支持分节. 并对PHP的常量进行支持.
- 在第一个运行的时候载入配置文件, 把格式化后的内容保持在内存中. 直到配置文件有了修改, 才会再次载入.
控制器
- 默认的模块/控制器/动作, 都是以Index命名的, 这是可通过配置文件修改的.
- 对于默认模块, 控制器的目录是在application目录下的controllers目录下, Action的命名规则是"名字+Action"
默认控制器application/controllers/Index.php
<?php
class IndexController extends Yaf_Controller_Abstract {
public function indexAction() {//默认Action
$this->getView()->assign("content", "Hello World");
}
}
?>
视图文件
- Yaf支持简单的视图引擎, 并且支持用户自定义自己的视图引擎, 比如Smarty.
- 对于默认模块, 视图文件的路径是在application目录下的views目录中以小写的action名的目录中.
默认Action的视图application/views/index/index.phtml
<html>
<head>
<title>Hello World</title>
</head>
<body>
<?php echo $content;?>
</body>
</html>
使用代码生成工具
Yaf提供了代码生成工具
代码生成工具的使用
php yaf_cg newapp #newapp 是生成的目录名
将得到的newapp 目录, 拷贝到Webserver的documentRoot目录下
配置文件
php.ini 配置项
php.ini
[yaf]
# 必要配置!!可以在项目中动态动态调整,来适应不同的生产环境
yaf.environ = product
yaf.library = NULL
yaf.cache_config = 0
yaf.name_suffix = 1
yaf.name_separator = ""
yaf.forward_limit = 5
yaf.use_namespace = 0
yaf.use_spl_autoload = 0
配置解释:
yaf.environ
环境名称, 当用INI作为Yaf的配置文件时, 这个指明了Yaf将要在INI配置中读取的节的名字yaf.library
全局类库的目录路径yaf.cache_config
是否缓存配置文件(只针对INI配置文件生效), 打开此选项可在复杂配置的情况下提高性能yaf.name_suffix
在处理Controller, Action, Plugin, Model的时候, 类名中关键信息是否是后缀式, 比如UserModel, 而在前缀模式下则是ModelUseryaf.name_separator
在处理Controller, Action, Plugin, Model的时候, 前缀和名字之间的分隔符, 默认为空, 也就是UserPlugin, 加入设置为"_", 则判断的依据就会变成:"User_Plugin", 这个主要是为了兼容ST已有的命名规范yaf.forward_limit
forward最大嵌套深度yaf.use_namespace
开启的情况下, Yaf将会使用命名空间方式注册自己的类, 比如Yaf_Application将会变成Yaf\Applicationyaf.use_spl_autoload
开启的情况下, Yaf在加载不成功的情况下, 会继续让PHP的自动加载函数加载, 从性能考虑, 除非特殊情况, 否则保持这个选项关闭
application.ini配置项
- Yaf_Application初始化时刻需要给出的必要配置
- Yaf通过在不同的环境中, 选取不同的配置节, 再结合配置可继承, 来实现一套配置适应多种环境(线上,测试,开发).
必要配置
application.director
应用的绝对目录路径
可选的配置
| 名称 | 值类型 | 默认值 | 说明 |
| :-------- |: --------| :------- |:------- |
| 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开始引入 |
获取自定义配置文件:
//获取所有配置
print_r(Yaf_Application::app()->getConfig());
//获取单个配置
print_r(Yaf_Application::app()->getConfig()->redis);
自动加载器
Yaf在自启动的时候, 会通过SPL注册一个自己的Autoloader, 出于性能的考虑, 对于框架相关的MVC类, Yaf Autoloader只以目录映射的方式尝试一次.
目录映射规则:
| 类型 | 后缀(或者前缀, 可以通过php.ini中ap.name_suffix来切换) | 映射路径 |
| :-------- |: --------| :------- |
| 控制器 | Controller | 默认模块下为{项目路径}/controllers/, 否则为{项目路径}/modules/{模块名}/controllers/ |
| 数据模型 | Model | {项目路径}/models/ |
| 插件 | Plugin | {项目路径}/plugins/ |
全局类和自身类(本地类)
Yaf为了方便在一台服务器上部署的不同产品之间共享公司级别的共享库, 支持全局类和本地类两种加载方式.
- 全局类是指, 所有产品之间共享的类, 这些类库的路径是通过
yaf.library
在php.ini - 本地类是指, 产品自身的类库
类的加载规则
Yaf规定类名中必须包含路径信息, 也就是以下划线"_"分割的目录信息. Yaf将依照类名中的目录信息, 完成自动加载:
全局类:
一个映射的例子Zend_Dummy_Foo
//Yaf将在如下路径寻找类Foo_Dummy_Bar
{类库路径(php.ini中指定的yaf.library)}/Foo/Dummy/Bar.php
本地类:
//申明, 凡是以Foo和Local开头的类, 都是本地类
$loader = Yaf_Loader::getIgnstance();
$loader->registerLocalNamespace(array("Foo", "Local"));
//Yaf将在如下路径寻找类Foo_Dummy_Bar
{类库路径(conf/application.ini中指定的yaf.library)}/Foo/Dummy/Bar.php
手动导入文件:
Yaf_Loader::import('conf/NetWorkCode.php');
echo NetWorkCode::NETWORK_ERROR;
Bootstrap
简介
Bootstrap, 也叫做引导程序. 它是Yaf提供的一个全局配置的入口, 在Bootstrap中, 你可以做很多全局自定义的工作.
使用Bootstrap
在一个Yaf_Application被实例化之后, 运行(Yaf_Application::run)之前, 可选的我们可以运行Yaf_Application::bootstrap
<?php
$app = new Yaf_Application("conf.ini");
$app
->bootstrap() //可选的调用
->run();
}
当bootstrap被调用的时刻, Yaf_Application
就会默认的在APPLICATION_PATH
下, 寻找Bootstrap.php
, 而这个文件中, 必须定义一个Bootstrap类, 而这个类也必须继承自Yaf_Bootstrap_Abstract
.
实例化成功之后, 所有在Bootstrap类中定义的, 以_init
开头的方法, 都会被依次调用, 而这些方法都可以接受一个Yaf_Dispatcher
实例作为参数.
<?php
/**
* 所有在Bootstrap类中, 以_init开头的方法, 都会被Yaf调用,
* 这些方法, 都接受一个参数:Yaf_Dispatcher $dispatcher
* 调用的次序, 和申明的次序相同
*/
class Bootstrap extends Yaf_Bootstrap_Abstract{
public function _initConfig() {
$config = Yaf_Application::app()->getConfig();
Yaf_Registry::set("config", $config);
}
public function _initDefaultName(Yaf_Dispatcher $dispatcher) {
$dispatcher->setDefaultModule("Index")->setDefaultController("Index")->setDefaultAction("index");
}
}
插件
简介
Yaf支持用户定义插件来扩展Yaf的功能. 它们都必须继承自Yaf_Plugin_Abstract. 插件要发挥功效, 也必须现实的在Yaf中进行注册, 然后在适当的实际, Yaf就会调用它.
Yaf支持的Hook
| 触发顺序 | 名称 | 触发时机 | 说明 |
| :-------- |: --------| :------- |:------- |
| 1 | routerStartup | 在路由之前触发 | 这个是7个事件中, 最早的一个. 但是一些全局自定的工作, 还是应该放在Bootstrap中去完成 |
| 2 | routerShutdown | 路由结束之后触发 | 此时路由一定正确完成, 否则这个事件不会触发 |
| 3 | dispatchLoopStartup | 分发循环开始之前被触发 |
| 4 | preDispatch | 分发之前触发 | 如果在一个请求处理过程中, 发生了forward, 则这个事件会被触发多次 |
| 5 | postDispatch | 分发结束之后触发 | 此时动作已经执行结束, 视图也已经渲染完成. 和preDispatch类似, 此事件也可能触发多次 |
| 6 | dispatchLoopShutdown | 分发循环结束之后触发 | 此时表示所有的业务逻辑都已经运行完成, 但是响应还没有发送 |
定义插件
- 继承自Yaf_Plugin_Abstract
- 需要在插件类中定义和上面事件同名的方法
- 方法就会在该事件触发的时候被调用
- 插件方法, 可以接受俩个参数, Yaf_Request_Abstract实例和Yaf_Response_Abstract实例
<?php
class UserPlugin 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) {
}
}
注册插件
向Yaf_Dispatcher
注册插件, 一般的插件注册都会放在Bootstrap
中进行
<?php
class Bootstrap extends Yaf_Bootstrap_Abstract{
public function _initPlugin(Yaf_Dispatcher $dispatcher) {
$user = new UserPlugin();
$dispatcher->registerPlugin($user);
}
}
插件目录
放置在APPLICATION_PATH
下的plugins
目录, 这样在自动加载的时候, 加载器通过类名, 发现这是个插件类
路由和路由协议
概述
路由器主要负责解析一个请求并且决定什么module、controller、action被请求;它同时也定义了一种方法来实现用户自定义路由,这也使得它成为最重要的一个MVC组组件.
路由组件有两个部分:路由器(Yaf_Router)和路由协议(Yaf_Route_Abstract).
默认情况下,我们的路由器是Yaf_Router, 而默认使用的路由协议是Yaf_Route_Static,是基于HTTP路由的
路由类别
Yaf_Route_Simple
Yaf_Route_Supervar
Yaf_Route_Static
Yaf_Route_Map
Yaf_Route_Rewrite
Yaf_Route_Regex
默认路由协议
默认的路由协议Yaf_Route_Static
, 就是分析请求中的request_uri
, 在去除掉base_uri以后, 获取到真正的负载路由信息的request_uri片段, 具体的策略是, 根据"/"对request_uri分段, 依次得到Module,Controller,Action,
在得到Module以后, 还需要根据Yaf_Application::$modules
来判断Module是否是合法的Module, 如果不是, 则认为Module并没有体现在request_uri中, 而把原Module当做Controller, 原Controller当做Action:
工作中默认的即可满足需求,如果有需要可以自己定制
具体参考:http://www.laruence.com/manual/yaf.routes.html
简单路由
/*
* http://yaf.test.com/?m=order&c=orderinfo&a=show
*/
// $router=$dispatcher->getRouter();
// $route = new Yaf_Route_Simple("m", "c", "a");
// $router->addRoute("name", $route);