anpv1 / iceage-php
闪电般的微型PHP框架
1.0.5
2020-04-06 07:45 UTC
Requires
- php: >=5.3.0
Requires (Dev)
- phpunit/phpunit: ^6.2
README
IceAge 是一个闪电般快速且极小的 PHP 纳米框架,总代码量约为 350 行。IceAge 提供了一个非常简单、但强大且灵活的接口,用于构建基于 Web 的应用程序。
在我的联想 U4170 上,Intel Core i5 5200U,4GB RAM,使用 apache bench,一个全页面使用 IceAge 和 dotenv 加载环境变量,Twig 作为模板引擎以及一个 PDO MySQL 查询可以达到 1639.09 请求/秒。使用 IceAge 的“Hello, world!”页面可以达到 10167.46 请求/秒。
Hello, world!
<?php // index.php // composer autoload, install any dependencies you need require_once('../vendor/autoload.php'); $app = new \IceAge\Application(); // routes definition $app->get('/', function(){return 'Hello, world!';}); $result = $app->run(); $app->response($result);
路由
// Routing with regex definition of parameters and multiple methods // id in URL must be digit to match $app->route( '/hello/:id|[0-9]+|', '\\App\\Controller\\Hello::get', 'GET|POST' ); // optional parameters // this will match /blog/2017, /blog/2017/07, /blog/2017/07/01 $app->get('/blog(/:year|[\d]{4}|(/:month|[\d]{2}|(/:day|[\d]{2}|)?)?)?', function($route_params){ return $route_params; }); // grouping routes $app->group('/admin', function(){ $this->get('/photo', function(){ return 'PhotoAdmin'; }); // match /admin/photo $this->post('/gallery', function(){ return 'GalleryAdmin'; }); // match /admin/gallery })->middleware(function($required_login){ if($required_login){ return 'RequiredLogin'; } }, array('required_login' => 1));
使用服务
IceAge 支持 2 个主要特性:路由和服务管理。您可以使用 register 方法将服务注册到应用程序中
<?php // index.php // composer autoload, install any dependencies you need require_once('../vendor/autoload.php'); use \Twig_Environment as Twig; $app = new \IceAge\Application(); // register $db service $app->register('db', function(){ return new \PDO( $_ENV['DB_DSN'], $_ENV['DB_USER'], $_ENV['DB_PASSWORD'], array( \PDO::ATTR_PERSISTENT => true ) ); }); // register Twig_Environment template $app->register('Twig_Environment', function(){ $loader = new \Twig_Loader_Filesystem(realpath('app/templates/views')); return new Twig($loader, array( 'cache' => realpath('app/templates/cache'), 'auto_reload' => true )); }); // routes definition // in the route handler you can use the $db service which is a PDO instance // and load any parameter name which is a Twig_Environment instance $app->get('/', function($db, Twig $template){ return $template->render('template.html', array('message' => 'Hello, world!')); }); $result = $app->run(); $app->response($result);
如上例所示,服务可以通过其名称($db)或其类名(Twig_Environment)来加载
启动应用程序
IceAge 应用程序对象支持一个 bootstrap 方法,可以用来注册所有服务和路由处理程序。例如
<?php // public/index.php chdir(getcwd().'/../'); // composer autoload, install any dependencies you need require_once('vendor/autoload.php'); $app = new \IceAge\Application(); $app->bootstrap(array( '\\App\\Bootstrap\\Env::load', '\\App\\Bootstrap\\Services::register', '\\App\\Bootstrap\\Routes::register' )); try { $result = $app->run(); } catch(Exception $e){ $response = $app->run_handler('\\App\\Controller\\Error::error', array('error' => $e)); $result = $app->response($response); } $app->response($result);
<?php // app/Bootstrap/Env.php namespace App\Bootstrap; use Rfussien\Dotenv\Loader; class Env { public static function load(){ $dotenv = new Loader('app/'); $dotenv->load(); } }
<?php // app/Bootstrap/Routes.php namespace App\Bootstrap; class Routes { public static function register($app){ // routes definition $app->get('/', '\\App\\Controller\\Index::get'); $app->get('/login', '\\App\\Controller\\Login::index'); $app->route( '/hello/:name/:id', '\\App\\Controller\\Hello::get', 'GET|POST' ); $app->get('/group/get/:id', '\\App\\Controller\\Group::get'); $app->post('/user/signin', '\\App\\Controller\\Login::signin'); } }
<?php // app/Bootstrap/Services.php namespace App\Bootstrap; class Services { private static $dbh; private static $twig; private static $acl; public static function register($app){ $app->register('db', '\\App\\Bootstrap\\Services::db_service'); $app->register('twig', '\\App\\Bootstrap\\Services::twig_service'); } public static function db_service(){ if(!self::$dbh){ self::$dbh = new \PDO( $_ENV['DB_DSN'], $_ENV['DB_USER'], $_ENV['DB_PASSWORD'], array( \PDO::ATTR_PERSISTENT => true ) ); } return self::$dbh; } public static function twig_service(){ if(!self::$twig){ $loader = new \Twig_Loader_Filesystem(realpath('app/templates/views')); self::$twig = new \Twig_Environment($loader, array( 'cache' => realpath('app/templates/cache'), 'auto_reload' => true )); } return self::$twig; } }
<?php // app/Controller/Hello.php namespace App\Controller; use App\DataTable\TestTbl; class Hello { // $route_params is a special service to get the parameters defined on route // In this case the route is /hello/:name/:id // So if the request URL is /hello/Bob/1 then $route_params['name'] = "Bob" // $route_params['id'] = 1 public static function get($twig, $db, $route_params) { $test_tbl = new TestTbl($db); $row = $test_tbl->get($route_params['id']); return $twig->render('hello/index.html', array('row' => $row)); } }
<?php // app/Controller/Error.php namespace App\Controller; class Error { // $error is passed from the below line in index.php // $response = $app->run_handler('\\App\\Controller\\Error::error', array('error' => $e)); public static function error($twig, $error){ return $twig->render('error/index.html', array('error' => $error, 'debug' => $_ENV['DEBUG_MODE'])); } }
请求生命周期
- bootstrap 函数被调用,传入 IceAge 应用程序对象的实例
- 应用程序对象将尝试找到匹配的路由
- 如果没有匹配的路由,将抛出一个 IceAge\Exception 异常,代码为 IceAge\Exception::NO_ROUTE 并退出
- 如果有一个匹配的路由,IceAge 应用程序将运行存在的路由中间件。
- 如果路由中间件处理程序运行并返回响应,IceAge 应用程序将跳过路由处理程序并进入输出处理步骤。
- 如果路由中间件没有返回值,IceAge 应用程序将加载路由处理程序使用的所有服务,然后使用加载的服务调用路由处理程序,并获取响应。
- 根据路由处理程序的响应
- 如果是字符串,IceAge 会立即将字符串作为输出发送到浏览器。
- 如果是 \Psr\Http\Message\ResponseInterface 的实例,IceAge 使用 \Zend\Diactoros 生成输出并发送到浏览器。
- 在其他情况下,IceAge 使用 json_encode 函数生成输出,并通过 Content-type: application/json 头部发送。
要注册路由中间件,您可以使用路由对象的 middleware 方法
<?php $app->get('/', '\\App\\Controller\\Index::get') // middleware handler can use any registered services and params passed on ->middleware(function($db, $permission){ // $permission = "admin" // implement middleware here }, array('permission' => 'admin')) ->middleware(function($login_required){ // $login_required = True // implement middleware here }, array('login_required' => True));