Flight 一个可扩展的PHP微框架

沈开畅
2023-12-01

用户指南


路由

路由在 Flight 中是通过与一个回调函数匹配的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'));
    

路由的匹配根据顺序定义。第一个匹配的路由请求将被调用。

路由方法

默认情况下,路由模式匹配的方法允许所有请求。你可以对特定的方法将一个标识符放在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。

通配符

如果你想在单独URL部分匹配多个片段的路由。可以使用 “*” 通配符。


    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
    });
    

扩展

Flight 被设计成一个可扩展的框架。框架附带了一组默认的方法和组件,但是她允许您映射的自己的方法,注册自己的类,或者覆盖现有的类和方法。

映射方法

映射你自己的方法,通过 “map” 方法:


    // Map your method
    Flight::map('hello', function($name){
        echo "hello $name!";
    });

    // Call your custom method
    Flight::hello('Bob');
    

注册类

注册你自己的类,您可以使用 “register” 方法:


    // Register your class
    Flight::register('user', 'User');

    // Get an instance of your class
    $user = Flight::user();
    

注册方法还允许为你的类构造函数传递参数。因此,当加载你的自定义类,她将预初始化。你可以定义的构造函数参数传递额外的数组。这里有一个加载数据库连接的例子:


    // Register class with constructor parameters
    Flight::register('db', 'PDO', array('mysql:host=localhost;dnbname=test','user','pass'));

    // Get an instance of your class
    // This will create an object with the defined parameters
    //
    //     new PDO('mysql:host=localhost;dnbname=test','user','pass');
    //
    $db = Flight::db();
    

如果你加了一个额外的回调参数,她将在类构建后立即执行。这允许你在新对象执行任何程序设置。回调函数接受一个参数,新对象的一个实例。


    // The callback will be passed the object that was constructed
    Flight::register('db', 'PDO', array('mysql:host=localhost;dnbname=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();
    

Framework 的 “map” 和 “register” 方法不能被覆盖。如果你这样做,会得到一个错误。


过滤

Flight 允许你在调用之前和之后使用过滤方法。你需要记住它没有预定义的钩子。您可以过滤任何默认的框架方法以及任何你自定义的映射方法。

一个过滤器函数如下所示:


    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;
    });

    // This will not get called
    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; ?>'!
    

她将输出:


    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 server。您可以通过改变配置启用她:


    Flight::set('flight.log_errors', true);
    

没有找到

当一个 URL 没有被找到, Flight 将调用 notFound 方法。默认行为是发送一个 HTTP 404 Not Found 响应,来显示一些简单的错误信息。

你可以根据自己的需求覆盖此行为:


    Flight::map('notFound', function(){
        // Handle not found
    });
    

重定向

您可以传递一个新的 URL 通过 “redirect” 方法重定向。:


    Flight::redirect('/new/location');
    

默认情况下 Flight 发送一个 HTTP 303 状态码。你可以自定义一个代码:


    Flight::redirect('/new/location', 401);
    

请求

Flight 封装 HTTP 请求到一个对象, 你可以通过这样访问:


    $request = Flight::request();
    

请求对象提供了以下属性:


    url - 被请求的 URL
    base - 被请求 URL 的父目录
    method - 请求方法 (GET, POST, PUT, DELETE)
    referrer - 引用的 URL
    ip - 客户机的 IP 地址
    ajax - 是不是一个 AJAX 请求
    scheme - 服务器协议 (http, https)
    user_agent - 浏览器的信息
    body - 请求主体的原始数据
    type - 内容类型
    length - 内容长度
    query - 查询字符串参数
    data - Post 参数
    cookies - Cookie 参数
    files - 上传的文件
    secure - 连接是否安全
    accept - HTTP 接受参数
    proxy_ip - 代理客户机的 IP 地址
    

你可以通过数组或对象访问 querydatacookies 和 files 属性。

因此,要查询一个参数, 你可以这样:


    $id = Flight::request()->query['id'];
    

或者这样:


    $id = Flight::request()->query->id;
    

HTTP 缓存

Flight 提供了内置的 HTTP 缓存。如果缓存条件满足, Flight 将返回一个 HTTP 304 Not Modified 响应。下次客户端请求相同的资源时,她们会提示使用本地缓存版本。

最后修改

你可以使用 lastModified 传递一个 UNIX 时间戳来设置页面最后修改日期和时间。客户端将继续使用缓存,直到最后修改值发生了改变。


    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 方法用于 JSONP 请求。你可以通过传递查询参数名来定义你正在使用的回调函数:


    Flight::jsonp(array('id' => 123), 'q');
    

所以,当制造一个GET请求,使用 ?q=my_func ,你会得到这样的输出:


    my_func({"id":123});
    

如果你不传递查询参数名将默认使用 jsonp 。


配置

您可以自定义 Flight 的某些行为,通过使用 set 方法。


    Flight::set('flight.log_errors', true);
    

下面是一个所有可用配置的列表。


    flight.base_url - 覆盖 base url 请求。 (默认: null)
    flight.handle_errors - 允许 Flight 处理所有内部错误。 (默认: true)
    flight.log_errors - 将错误日志记录到 web server 的错误日志文件。 (默认: false)
    flight.views.path - 包含视图模板文件的目录 (默认: ./views)
    

框架方法

Flight 被设计为易于使用和理解。下面是框架的全套方法。它包含的核心方法,常规的静态方法,和可扩展的方法,可以过滤或覆盖。

核心方法


    Flight::map($name, $callback) // 创建一个自定义框架的方法。
    Flight::register($name, $class, [$params], [$callback]) // 注册一个类的框架方法。
    Flight::before($name, $callback) // 在一个框架方法之前添加一个过滤器。
    Flight::after($name, $callback) // 在一个框架方法之后添加一个过滤器。
    Flight::path($path) // 添加了一个半自动的类路径。
    Flight::get($key) // 得到一个变量。
    Flight::set($key, $value) // 设置一个变量。
    Flight::has($key) // 检查一个变量是否设置。
    Flight::clear([$key]) // 清除一个变量。
    

可扩展的方法


    Flight::start() // 开始框架
    Flight::stop() // 停止该框架并发送一个响应。
    Flight::halt([$code], [$message]) // 停止该框架并带一个可选的状态代码和消息。
    Flight::route($pattern, $callback) // 映射一个 URL 模式到回调。
    Flight::redirect($url, [$code]) // 重定向到另一个URL。
    Flight::render($file, [$data], [$key]) // 呈现一个模板文件。
    Flight::error($exception) // 发送一个 HTTP 500 响应。
    Flight::notFound() // 发送一个 HTTP 404 响应。
    Flight::etag($id, [$type]) // 执行 ETag HTTP 缓存。
    Flight::lastModified($time) // 执行最后更改的 HTTP 缓存。
    Flight::json($data, [$code], [$encode]) // 发送一个 JSON 响应。
    Flight::jsonp($data, [$param], [$code], [$encode]) // 发送一个 JSONP 响应。
    

任何被 map 和 register 的自定义方法都可以被过滤。

框架实例

Flight 并不是作为一个全局静态类运行,您可以选择作为一个对象实例运行它。


    require 'flight/autoload.php';

    use flight\Engine;

    $app = new Engine();

    $app->route('/', function(){
        echo 'hello world!';
    });

    $app->start();
    

现在所有的静态方法都可以被作为常规的类方法。





待续.

 类似资料: