drmyersii/klein

一款针对 PHP 的闪电般快速的路由器

v2.1.1 2016-02-24 20:46 UTC

This package is not auto-updated.

Last update: 2024-09-20 17:37:49 UTC


README

Build Status

klein.php 是一个快速且灵活的 PHP 5.3+ 路由器

  • 灵活的正则表达式路由(灵感来自 Sinatra
  • 一组用于快速构建 Web 应用程序的样板方法
  • 几乎没有开销 => 2500+ 请求/秒

入门指南

  1. 需要 PHP 5.3.x
  2. 使用 Composer (推荐)或手动安装 Klein
  3. 设置 URL 重写,以便所有请求都由 index.php 处理
  4. (可选)为了安全起见,添加一些 APC

Composer 安装

  1. 获取 Composer
  2. 使用 php composer.phar require klein/klein 安装 Klein
  3. 将以下内容添加到您的应用程序主 PHP 文件中:require 'vendor/autoload.php';

示例

Hello World - 必要的 Hello World 示例

<?php
require_once __DIR__ . '/vendor/autoload.php';

$klein = new \Klein\Klein();

$klein->respond('GET', '/hello-world', function () {
    return 'Hello World!';
});

$klein->dispatch();

示例 1 - 响应所有请求

$klein->respond(function () {
    return 'All the things';
});

示例 2 - 命名参数

$klein->respond('/[:name]', function ($request) {
    return 'Hello ' . $request->name;
});

示例 3 - So RESTful

$klein->respond('GET', '/posts', $callback);
$klein->respond('POST', '/posts', $callback);
$klein->respond('PUT', '/posts/[i:id]', $callback);
$klein->respond('DELETE', '/posts/[i:id]', $callback);
$klein->respond('OPTIONS', null, $callback);

// To match multiple request methods:
$klein->respond(array('POST','GET'), $route, $callback);

// Or you might want to handle the requests in the same place
$klein->respond('/posts/[create|edit:action]?/[i:id]?', function ($request, $response) {
    switch ($request->action) {
        //
    }
});

示例 4 - 发送对象/文件

$klein->respond(function ($request, $response, $service) {
    $service->xml = function ($object) {
        // Custom xml output function
    }
    $service->csv = function ($object) {
        // Custom csv output function
    }
});

$klein->respond('/report.[xml|csv|json:format]?', function ($request, $response, $service) {
    // Get the format or fallback to JSON as the default
    $send = $request->param('format', 'json');
    $response->$send($report);
});

$klein->respond('/report/latest', function ($request, $response, $service) {
    $response->file('/tmp/cached_report.zip');
});

示例 5 - 全部组合

$klein->respond(function ($request, $response, $service, $app) use ($klein) {
    // Handle exceptions => flash the message and redirect to the referrer
    $klein->onError(function ($klein, $err_msg) {
        $klein->service()->flash($err_msg);
        $klein->service()->back();
    });

    // The fourth parameter can be used to share scope and global objects
    $app->db = new PDO(...);

    // $app also can store lazy services, e.g. if you don't want to
    // instantiate a database connection on every response
    $app->register('db', function() {
        return new PDO(...);
    });
});

$klein->respond('POST', '/users/[i:id]/edit', function ($request, $response, $service, $app) {
    // Quickly validate input parameters
    $service->validateParam('username', 'Please enter a valid username')->isLen(5, 64)->isChars('a-zA-Z0-9-');
    $service->validateParam('password')->notNull();

    $app->db->query(...); // etc.

    // Add view properties and helper methods
    $service->title = 'foo';
    $service->escape = function ($str) {
        return htmlentities($str); // Assign view helpers
    };

    $service->render('myview.phtml');
});

// myview.phtml:
<title><?php echo $this->escape($this->title) ?></title>

路由命名空间

$klein->with('/users', function () use ($klein) {

    $klein->respond('GET', '/?', function ($request, $response) {
        // Show all users
    });

    $klein->respond('GET', '/[:id]', function ($request, $response) {
        // Show a single user
    });

});

foreach(array('projects', 'posts') as $controller) {
    // Include all routes defined in a file under a given namespace
    $klein->with("/$controller", "controllers/$controller.php");
}

包含的文件在 Klein 的作用域内运行($klein),因此可以使用 $this 访问所有 Klein 方法/属性

示例文件: "controllers/projects.php"

// Routes to "/projects/?"
$this->respond('GET', '/?', function ($request, $response) {
    // Show all projects
});

懒加载服务

可以将服务存储为 懒加载,这意味着它们仅在首次使用时才实例化。

<?php
$klein->respond(function ($request, $response, $service, $app) {
    $app->register('lazyDb', function() {
        $db = new stdClass();
        $db->name = 'foo';
        return $db;
    });
});

//Later

$klein->respond('GET', '/posts', function ($request, $response, $service, $app) {
    // $db is initialised on first request
    // all subsequent calls will use the same instance
    return $app->lazyDb->name;
});

验证器

要添加自定义验证器,请使用 addValidator($method, $callback)

$service->addValidator('hex', function ($str) {
    return preg_match('/^[0-9a-f]++$/i', $str);
});

您可以使用 is<$method>()not<$method>() 验证参数,例如。

$service->validateParam('key')->isHex();

或者,您可以使用相同的流程验证任何字符串。

$service->validate($username)->isLen(4,16);

验证方法是可以链式的,并且可以指定自定义异常消息,以在验证失败时使用

$service->validateParam('key', 'The key was invalid')->isHex()->isLen(32);

路由

[ match_type : param_name ]

一些示例

*                    // Match all request URIs
[i]                  // Match an integer
[i:id]               // Match an integer as 'id'
[a:action]           // Match alphanumeric characters as 'action'
[h:key]              // Match hexadecimal characters as 'key'
[:action]            // Match anything up to the next / or end of the URI as 'action'
[create|edit:action] // Match either 'create' or 'edit' as 'action'
[*]                  // Catch all (lazy)
[*:trailing]         // Catch all as 'trailing' (lazy)
[**:trailing]        // Catch all (possessive - will match the rest of the URI)
.[:format]?          // Match an optional parameter 'format' - a / or . before the block is also optional

更多复杂示例

/posts/[*:title][i:id]     // Matches "/posts/this-is-a-title-123"
/output.[xml|json:format]? // Matches "/output", "output.xml", "output.json"
/[:controller]?/[:action]? // Matches the typical /controller/action format

注意 - 所有 与请求 URI 匹配的路由都会被调用 - 这允许您整合复杂的条件逻辑,如用户身份验证或视图布局。例如,以下代码将包装其他路由的标题和页脚

$klein->respond('*', function ($request, $response, $service) { $service->render('header.phtml'); });
//other routes
$klein->respond('*', function ($request, $response, $service) { $service->render('footer.phtml'); });

路由自动匹配整个请求 URI。如果您需要匹配请求 URI 的部分或使用自定义正则表达式,请使用 @ 操作符。如果您需要否定路由,请使用 ! 操作符

// Match all requests that end with '.json' or '.csv'
$klein->respond('@\.(json|csv)$', ...

// Match all requests that _don't_ start with /admin
$klein->respond('!@^/admin/', ...

视图

您可以通过将它们分配给 $service 对象或将它们作为 $service->render() 的第二个参数传递,将属性或助手发送到视图

$service->escape = function ($str) {
    return htmlentities($str);
};

$service->render('myview.phtml', array('title' => 'My View'));

// Or just: $service->title = 'My View';

myview.phtml

<title><?php echo $this->escape($this->title) ?></title>

视图在 $service 的作用域内编译和运行,因此可以使用 $this 访问所有服务方法

$this->render('partial.html')           // Render partials
$this->sharedData()->get('myvar')       // Access stored service variables
echo $this->query(array('page' => 2))   // Modify the current query string

API

以下列出了您最有可能使用的常用类中的公共方法。有关更正式的类/方法文档,请参阅 PHPdoc 生成的文档

$request->
    id($hash = true)                    // Get a unique ID for the request
    paramsGet()                         // Return the GET parameter collection
    paramsPost()                        // Return the POST parameter collection
    paramsNamed()                       // Return the named parameter collection
    cookies()                           // Return the cookies collection
    server()                            // Return the server collection
    headers()                           // Return the headers collection
    files()                             // Return the files collection
    body()                              // Get the request body
    params()                            // Return all parameters
    params($mask = null)                // Return all parameters that match the mask array - extract() friendly
    param($key, $default = null)        // Get a request parameter (get, post, named)
    isSecure()                          // Was the request sent via HTTPS?
    ip()                                // Get the request IP
    userAgent()                         // Get the request user agent
    uri()                               // Get the request URI
    pathname()                          // Get the request pathname
    method()                            // Get the request method
    method($method)                     // Check if the request method is $method, i.e. method('post') => true
    query($key, $value = null)          // Get, add to, or modify the current query string
    <param>                             // Get / Set (if assigned a value) a request parameter

$response->
    protocolVersion($protocol_version = null)       // Get the protocol version, or set it to the passed value
    body($body = null)                              // Get the response body's content, or set it to the passed value
    status()                                        // Get the response's status object
    headers()                                       // Return the headers collection
    cookies()                                       // Return the cookies collection
    code($code = null)                              // Return the HTTP response code, or set it to the passed value
    prepend($content)                               // Prepend a string to the response body
    append($content)                                // Append a string to the response body
    isLocked()                                      // Check if the response is locked
    requireUnlocked()                               // Require that a response is unlocked
    lock()                                          // Lock the response from further modification
    unlock()                                        // Unlock the response
    sendHeaders($override = false)                  // Send the HTTP response headers
    sendCookies($override = false)                  // Send the HTTP response cookies
    sendBody()                                      // Send the response body's content
    send()                                          // Send the response and lock it
    isSent()                                        // Check if the response has been sent
    chunk($str = null)                              // Enable response chunking (see the wiki)
    header($key, $value = null)                     // Set a response header
    cookie($key, $value = null, $expiry = null)     // Set a cookie
    cookie($key, null)                              // Remove a cookie
    noCache()                                       // Tell the browser not to cache the response
    redirect($url, $code = 302)                     // Redirect to the specified URL
    dump($obj)                                      // Dump an object
    file($path, $filename = null)                   // Send a file
    json($object, $jsonp_prefix = null)             // Send an object as JSON or JSONP by providing padding prefix

$service->
    sharedData()                                    // Return the shared data collection
    startSession()                                  // Start a session and return its ID
    flash($msg, $type = 'info', $params = array()   // Set a flash message
    flashes($type = null)                           // Retrieve and clears all flashes of $type
    markdown($str, $args, ...)                      // Return a string formatted with markdown
    escape($str)                                    // Escape a string
    refresh()                                       // Redirect to the current URL
    back()                                          // Redirect to the referer
    query($key, $value = null)                      // Modify the current query string
    query($arr)
    layout($layout)                                 // Set the view layout
    yieldView()                                     // Call inside the layout to render the view content
    render($view, $data = array())                  // Render a view or partial (in the scope of $response)
    partial($view, $data = array())                 // Render a partial without a layout (in the scope of $response)
    addValidator($method, $callback)                // Add a custom validator method
    validate($string, $err = null)                  // Validate a string (with a custom error message)
    validateParam($param, $err = null)                  // Validate a param
    <callback>($arg1, ...)                          // Call a user-defined helper
    <property>                                      // Get a user-defined property

$app->
    <callback>($arg1, ...)                          //Call a user-defined helper

$validator->
    notNull()                           // The string must not be null
    isLen($length)                      // The string must be the exact length
    isLen($min, $max)                   // The string must be between $min and $max length (inclusive)
    isInt()                             // Check for a valid integer
    isFloat()                           // Check for a valid float/decimal
    isEmail()                           // Check for a valid email
    isUrl()                             // Check for a valid URL
    isIp()                              // Check for a valid IP
    isAlpha()                           // Check for a-z (case insensitive)
    isAlnum()                           // Check for alphanumeric characters
    contains($needle)                   // Check if the string contains $needle
    isChars($chars)                     // Validate against a character list
    isRegex($pattern, $modifiers = '')  // Validate against a regular expression
    notRegex($pattern, $modifiers ='')
    is<Validator>()                     // Validate against a custom validator
    not<Validator>()                    // The validator can't match
    <Validator>()                       // Alias for is<Validator>()

单元测试

单元测试是开发像Klein这样的路由引擎的重要组成部分。增加的功能或错误修复可能在没有大量测试的情况下产生难以发现的不利影响,因此单元测试的重要性。

本项目使用PHPUnit作为其单元测试框架。

所有测试都位于/tests目录中,每个测试都扩展了一个抽象类AbstractKleinTest

要测试项目,只需运行php composer.phar install --dev以使用composer下载PHPUnit的通用版本,然后从主目录使用./vendor/bin/phpunit运行测试

贡献

有关更多信息,请参阅贡献指南

更多信息

有关更多信息,请参阅wiki

贡献者

许可证

(MIT许可证)

版权(c)2010 Chris O'Hara cohara87@gmail.com

特此授予任何人免费获得此软件及其相关文档文件(“软件”)副本的权限,用于无限制地处理软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本,并允许向软件提供的人士从事此类活动,前提是遵守以下条件

上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。

软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、适用于特定目的和无侵权性的保证。在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论该责任是基于合同、侵权或其他原因,是否因软件或软件的使用或其他方式产生。