Flight-一个简洁快速的php框架
Flight是一款非常小巧的框架,相比传统的框架,飞行?飞机?(作者这名字有意思,滑稽)框架就像它的名字一样,同时重写功能是这个框架的特色,通过重写部分可以很好的自定义自己需要的功能,达到快速上手的目的,本文翻译值Flight在github上的介绍,如果有错误的地方,可以在下面留言。
What is Flight?
Flight是一个快速,简单,可扩展的PHP框架。帮助你快速轻松地构建RESTful Web应用程序。
require 'flight/Flight.php';
Flight::route('/', function(){
echo 'hello world!';
});
Flight::start();
要求
PHP 5.3
或者以上
协议
Flight使用MIT协议开源。
安装
1. 下载下面文件.
如果你使用Composer,可以执行下面命令安装:
composer require mikecao/flight
或者点击下载,然后解压到你的程序目录.
2. 服务器配置.
使用 Apache, 在.htaccess
文件里添加下面内容:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
注意: 如果你在子目录中安装Flight,请在 RewriteEngine On
后面添加 RewriteBase /subdir/
。
使用 Nginx, 添加下面内容到配置文件中:
server {
location / {
try_files $uri $uri/ /index.php;
}
}
3. 新建index.php
。
首先,加载Flight。
require 'flight/Flight.php';
如果你使用Composer, 则使用自动加载器。
require 'vendor/autoload.php';
定义一个路由,并分配路由处理函数。
Flight::route('/', function(){
echo 'hello world!';
});
最后,开始使用Flight
Flight::start();
路由
当一个URL规则被匹配到时,便会调取回调函数。
Flight::route('/', function(){
echo 'hello world!';
});
回调可以是任何可调用的对象,可以是一个常规函数:
function hello(){
echo 'hello world!';
}
Flight::route('/', 'hello');
或者是一个类:
class Greeting {
public static function hello() {
echo 'hello world!';
}
}
Flight::route('/', array('Greeting', 'hello'));
或者一个对象的方法:
class Greeting
{
public function __construct() {
$this->name = 'John Doe';
}
public function hello() {
echo "Hello, {$this->name}!";
}
}
$greeting = new Greeting();
Flight::route('/', array($greeting, 'hello'));
路由根据注册的先后顺序匹配,先匹配到的会先被调用。
请求方式
默认情况下,路由模式与所有请求方式匹配,可以通过在URL之前放置标识符来响应特定请求方式。
Flight::route('GET /', function(){
echo 'I received a GET request.';
});
Flight::route('POST /', function(){
echo 'I received a POST request.';
});
你也可以使用|
分隔符将不同的请求方式映射到同一个回调上:
Flight::route('GET|POST /', function(){
echo 'I received either a GET or a POST request.';
});
正则表达式
可以在路由上使用正则表达式来匹配:
Flight::route('/user/[0-9]+', function(){
// This will match /user/1234
});
命名参数
您可以在路由中指定命名参数,这些参数将被传递到你的回调函数(译注:注意顺序)。
Flight::route('/@name/@id', function($name, $id){
echo "hello, $name ($id)!";
});
你也可以在命名参数后面添加正则表达式,并用:
分割开:
Flight::route('/@name/@id:[0-9]{3}', function($name, $id){
// This will match /bob/123
// But will not match /bob/12345
});
可选参数
你也可以使用括号包裹起来,表示可选参数:
Flight::route('/blog(/@year(/@month(/@day)))', function($year, $month, $day){
// This will match the following URLS:
// /blog/2012/12/10
// /blog/2012/12
// /blog/2012
// /blog
});
没有匹配到的参数值为NULL
通配符
上面的例子只能匹配到单个网段,如果你想匹配到多个网段,你可以使用*
通配符:
Flight::route('/blog/*', function(){
// This will match /blog/2000/02/01
});
使用一个回调函数响应所有请求:
Flight::route('*', function(){
// Do something
});
冒泡
你可以在回调函数返回true
来执行下一个匹配到的路由:
Flight::route('/user/@name', function($name){
// Check some condition
if ($name != "Bob") {
// Continue to next route
return true;
}
});
Flight::route('/user/*', function(){
// This will get called
});
路由信息
如果你想获取路由信息,你可以设置route
方法的第三个参数为true
,这样路由对象会作为 最后一个参数 传入回调函数:
Flight::route('/', function($route){
// Array of HTTP methods matched against
$route->methods;
// Array of named parameters
$route->params;
// Matching regular expression
$route->regex;
// Contains the contents of any '*' used in the URL pattern
$route->splat;
}, true);
扩展
Flight被设计成一个可扩展的框架。框架提供了一组默认方法和组件,但它允许你添加自己的方法和类,甚至覆盖原有方法和类。
映射方法
使用map
方法映射自定义方法:
// Map your method
Flight::map('hello', function($name){
echo "hello $name!";
});
// 调用自定义方法
Flight::hello('Bob');
注册类
使用register
方法注册自定义类:
// Register your class
Flight::register('user', 'User');
// Get an instance of your class
$user = Flight::user();
register
方法允许你在注册的时候添加要传递的参数,注册的类初始化时将传入设定的参数。
这是一个加载数据库连接的例子:
// Register class with constructor parameters
Flight::register('db', 'PDO', array('mysql:host=localhost;dbname=test','user','pass'));
// Get an instance of your class
// This will create an object with the defined parameters
//
// new PDO('mysql:host=localhost;dbname=test','user','pass');
//
$db = Flight::db();
register
方法允许你添加一个回调函数,回调函数将在注册类实例化后立即执行:
// The callback will be passed the object that was constructed
Flight::register('db', 'PDO', array('mysql:host=localhost;dbname=test','user','pass'), function($db){
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
});
默认情况下,每次加载类,都将得到一个共享的实例。要获得一个类的新实例,只需传入false
作为参数:
// Shared instance of the class
$shared = Flight::db();
// New instance of the class
$new = Flight::db(false);
注意:映射方法优先于注册类。 如果你使用相同的名称声明,则只会调用映射方法。
覆盖
Flight允许你覆盖其默认功能以满足需要,而无需修改任何代码。
栗子:当Flight没有匹配到一个URL时,它将会调用notFound
方法,并返回一个HTTP 404
代码,可以通过map
方法重写原来的方法:
Flight::map('notFound', function(){
// Display custom 404 page
include 'errors/404.html';
});
Flight允许你替换框架的核心组件。
栗子:使用你自定义类替换默认的路由类:
// Register your custom class
Flight::register('router', 'MyRouter');
// When Flight loads the Router instance, it will load your class
$myrouter = Flight::router();
框架自带类似map
和 register
的方法不能被重写,你就不要挣扎了。
过滤
Flight允许在调用之前和调用之后执行过滤器。没有预先定义的钩子你需要记住(原文:There are no predefined hooks you need to memorize.)。你可以过滤任何默认框架方法以及你映射的任何自定义方法。
一个过滤函数应该长这样子:
function(&$params, &$output) {
// Filter code
}
通过传入的参数,控制过滤器。
调用函数之前运行过滤器:
Flight::before('start', function(&$params, &$output){
// Do something
});
调用函数之后运行过滤器:
Flight::after('start', function(&$params, &$output){
// Do something
});
可以根据需要,向任何方法添加任意数量的过滤器,这些过滤器将按照注册的顺序被执行。
这是一个过滤过程的例子:
// Map a custom method
Flight::map('hello', function($name){
return "Hello, $name!";
});
// Add a before filter
Flight::before('hello', function(&$params, &$output){
// Manipulate the parameter
$params[0] = 'Fred';
});
// Add an after filter
Flight::after('hello', function(&$params, &$output){
// Manipulate the output
$output .= " Have a nice day!";
});
// Invoke the custom method
echo Flight::hello('Bob');
这个栗子会输出以下内容:
Hello Fred! Have a nice day!
如果定义多个过滤器,你可以在任意过滤器中返回false
,跳过其他过滤器:
Flight::before('start', function(&$params, &$output){
echo 'one';
});
Flight::before('start', function(&$params, &$output){
echo 'two';
// This will end the chain
return false;
});
// 这个过滤器不会被执行
Flight::before('start', function(&$params, &$output){
echo 'three';
});
注意, 核心方法例如 map
和 register
不能被过滤,因为它们被直接调用而不是动态调用。
变量
Flight允许你保存变量,以便它们在应用程序中的任何位置使用。
// Save your variable
Flight::set('id', 123);
// Elsewhere in your application
$id = Flight::get('id');
判断变量是否已经存在:
if (Flight::has('id')) {
// Do something
}
你也可以清除设置的变量:
// Clears the id variable
Flight::clear('id');
// Clears all variables
Flight::clear();
Flight还使用变量进行配置:
Flight::set('flight.log_errors', true);
视图(模板)
Flight默认提供一些基本的模板功能。通过向render
方法传入模板名和数据调用模板,数据参数可选:
Flight::render('hello.php', array('name' => 'Bob'));
传入的数据会自动注入模板,并且可以像局部变量一样引用。模板是一个简单的PHP文件。模板hello.php
内容如下:
Hello, '<?php echo $name; ?>'!
The output would be:
Hello, Bob!
你也可以使用set方法手动设置视图变量:
Flight::view()->set('name', 'Bob');
这样你就可以在所有模板里面使用name
变量:
Flight::render('hello');
注意:在render方法中指定模板的名称时,可以省略.php
扩展名。
默认情况下,Flight会在views
目录寻找模板文件,可以通过下面代码设置模板存放路径:
Flight::set('flight.views.path', '/path/to/views');
布局
通常现在的网站都有布局文件,可以在render
方法传入第三个参数,例如酱紫:
Flight::render('header', array('heading' => 'Hello'), 'header_content');
Flight::render('body', array('body' => 'World'), 'body_content');
这些视图将会保存到header_content
和body_content
变量中.这样子就可以渲染你的布局模板:
Flight::render('layout', array('title' => 'Home Page'));
模板文件大概长下面酱紫:
header.php
:
<h1><?php echo $heading; ?></h1>
body.php
:
<div><?php echo $body; ?></div>
layout.php
:
<html>
<head>
<title><?php echo $title; ?></title>
</head>
<body>
<?php echo $header_content; ?>
<?php echo $body_content; ?>
</body>
</html>
以上将会输出:
<html>
<head>
<title>Home Page</title>
</head>
<body>
<h1>Hello</h1>
<div>World</div>
</body>
</html>
自定义模板引擎
Flight允许替换原来的模板引擎,这是一个使用Smarty代替默认模板引擎的栗子:
// Load Smarty library
require './Smarty/libs/Smarty.class.php';
// Register Smarty as the view class
// Also pass a callback function to configure Smarty on load
Flight::register('view', 'Smarty', array(), function($smarty){
$smarty->template_dir = './templates/';
$smarty->compile_dir = './templates_c/';
$smarty->config_dir = './config/';
$smarty->cache_dir = './cache/';
});
// Assign template data
Flight::view()->assign('name', 'Bob');
// Display the template
Flight::view()->display('hello.tpl');
为了完整性,还应该覆盖Flight的默认渲染方法:
Flight::map('render', function($template, $data){
Flight::view()->assign($data);
Flight::view()->display($template);
});
错误处理
错误和异常
所有错误和异常都被Flight捕获并传递给error
方法。默认情况下会发送HTTP 500 Internal Server Error
和错误信息。
当然如果有需要,可以重写:
Flight::map('error', function(Exception $ex){
// Handle error
echo $ex->getTraceAsString();
});
默认情况下,错误不会记录到Web服务器。可以通过更改配置启用它:
Flight::set('flight.log_errors', true);
没有找到(Not Found)
如果URL没有被匹配,Flight会调用notFound
方法.默认情况下将会返回HTTP 404 Not Found
和错误信息.
如果想美化你的404页面,你依旧可以重写:
Flight::map('notFound', function(){
// Handle not found
});
重定向(Redirects)
可以向redirect
方法传入一个URL重定向当前请求:
Flight::redirect('/new/location');
默认情况下Flight会发送一个303状态码,你可以自定义状态码:
Flight::redirect('/new/location', 401);
请求(Requests)
Flight将HTTP请求封装到一个对象中,可以通过执行以下操作来访问:
$request = Flight::request();
这个请求对象提供以下属性:
url - The URL being requested
base - The parent subdirectory of the URL
method - The request method (GET, POST, PUT, DELETE)
referrer - The referrer URL
ip - IP address of the client
ajax - Whether the request is an AJAX request
scheme - The server protocol (http, https)
user_agent - Browser information
type - The content type
length - The content length
query - Query string parameters
data - Post data or JSON data
cookies - Cookie data
files - Uploaded files
secure - Whether the connection is secure
accept - HTTP accept parameters
proxy_ip - Proxy IP address of the client
可以把query
, data
, cookies
和files
当作一个对象或者数组访问:
例如,要获取请求字符串:
$id = Flight::request()->query['id'];
或者:
$id = Flight::request()->query->id;
原生请求体
To get the raw HTTP request body, for example when dealing with PUT requests, you can do:
$body = Flight::request()->getBody();
JSON Input
如果你发送一个类型为application/json
的请求,并且带有数据{"id": 123}
,可以通过data
属性访问这些数据:
$id = Flight::request()->data->id;
HTTP缓存
如若不理解,请阅读HTTP协议缓存部分
Flight为HTTP级别缓存提供内置支持。 如果满足缓存条件,Flight将返回304 Not Modified
的HTTP响应。 下一次客户端请求相同的资源时,将提示他们使用本地的缓存。
Last-Modified
可以通过向lastModified
方法传入一个UNIX时间戳来设置页面最后修改的时间和日期。如果lastModified
没有更改,客户端将一直使用本地缓存:
Flight::route('/news', function(){
Flight::lastModified(1234567890);
echo 'This content will be cached.';
});
ETag
ETag
缓存与Last-Modified
类似,你可以为你的资源设置一个ID:
Flight::route('/news', function(){
Flight::etag('my-unique-id');
echo 'This content will be cached.';
});
注意:调用lastModified
或etag
将同时设置和检查缓存值。如果缓存值在请求之间相同,则Flight将立即发送一个HTTP 304
响应并停止处理。
停止
可以使用在框架的任何地方使用halt
方法停止运行:
Flight::halt();
你也可以同时设置HTTP
状态码和返回信息:
Flight::halt(200, 'Be right back...');
调用halt
方法将并不会把当前内容输出,如果想停止框架并输出当前内容请使用stop
方法:
Flight::stop();
JSON
Flight支持发送json和jsonp响应,要发送json,你可以把数据传入json方法:
Flight::json(array('id' => 123));
** 译注:我并不熟悉JSONP,故下面内容不做翻译。 **
For JSONP requests you, can optionally pass in the query parameter name you are
using to define your callback function:
Flight::jsonp(array('id' => 123), 'q');
So, when making a GET request using ?q=my_func
, you should receive the output:
my_func({"id":123});
If you don't pass in a query parameter name it will default to jsonp
.
配置
可以使用set
方法修改Flight配置:
Flight::set('flight.log_errors', true);
所有可以修改的配置:
flight.base_url - Override the base url of the request. (default: null)
flight.case_sensitive - Case sensitive matching for URLs. (default: false)
flight.handle_errors - Allow Flight to handle all errors internally. (default: true)
flight.log_errors - Log errors to the web server's error log file. (default: false)
flight.views.path - Directory containing view template files. (default: ./views)
flight.views.extension - View template file extension. (default: .php)
框架方法
Flight特点是易于使用和理解。 以下是框架完整的方法列表,它由核心方法(不能被重写和过滤)和可扩展方法(可以被重写和过滤)组成。
核心方法
Flight::map($name, $callback) // Creates a custom framework method.
Flight::register($name, $class, [$params], [$callback]) // Registers a class to a framework method.
Flight::before($name, $callback) // Adds a filter before a framework method.
Flight::after($name, $callback) // Adds a filter after a framework method.
Flight::path($path) // Adds a path for autoloading classes.
Flight::get($key) // Gets a variable.
Flight::set($key, $value) // Sets a variable.
Flight::has($key) // Checks if a variable is set.
Flight::clear([$key]) // Clears a variable.
Flight::init() // Initializes the framework to its default settings.
Flight::app() // Gets the application object instance
可扩展方法
Flight::start() // Starts the framework.
Flight::stop() // Stops the framework and sends a response.
Flight::halt([$code], [$message]) // Stop the framework with an optional status code and message.
Flight::route($pattern, $callback) // Maps a URL pattern to a callback.
Flight::redirect($url, [$code]) // Redirects to another URL.
Flight::render($file, [$data], [$key]) // Renders a template file.
Flight::error($exception) // Sends an HTTP 500 response.
Flight::notFound() // Sends an HTTP 404 response.
Flight::etag($id, [$type]) // Performs ETag HTTP caching.
Flight::lastModified($time) // Performs last modified HTTP caching.
Flight::json($data, [$code], [$encode], [$charset], [$option]) // Sends a JSON response.
Flight::jsonp($data, [$param], [$code], [$encode], [$charset], [$option]) // Sends a JSONP response.
通过map
和register
注册的方法和类也可以使用过滤器。
框架实例化
不一定要将Flight作为全局静态类运行,你也可以选择将其作为对象实例化。
require 'flight/autoload.php';
use flight\Engine;
$app = new Engine();
$app->route('/', function(){
echo 'hello world!';
});
$app->start();
实例化后,你可以通过相同的名字,调用实例化后对象的方法。