Just for fun——Slim接力Swoole

2018-02-03 10:38:37来源:https://segmentfault.com/a/1190000013070940作者:SegmentFault人点击

分享
Slim

Slim 的话,是一个遵循 PSR (PSR 7)规范微型的框架,作者这样说:


Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs. At its core, Slim is a dispatcher that receives an HTTP request, invokes an appropriate callback routine, and returns an HTTP response. That’s it.


大致意思:slim的核心工作:分发了Http请求,然后调用回调函数,返回一个Http response对象。


Slim其实就帮我们做了两件事


路由的分发
依赖的注入

框架很小,所以别的部分(如db操作、模板引擎)可能需要自己实现,但slim通过依赖注入,让你可以很轻松的组装其他功能到slim中。


快速入门:
<?php
// Create and configure Slim app
$config = ['settings' => [
'addContentLengthHeader' => false,
]];
$app = new /Slim/App($config);
// Define app routes
$app->get('/hello/{name}', function ($request, $response, $args) {
return $response->write("Hello " . $args['name']);
});
// Run app
$app->run();

$request**代表了当前请求对象,**$response代表了当前响应对象,$args是占位符的键值对数组。


访问 /hello/salamander 就会输出 Hello salamander


添加依赖

DB 是我自己封装的一个PDO的操作类。


$config = ['settings' => [
'addContentLengthHeader' => false,
]];
$app = new /Slim/App($config);
$container = $app->getContainer();
$container['db'] = function($c) {
$dbHost = 'localhost';
$dbName = 'test';
$dbConf = [
'dsn' => "mysql:dbname={$dbName};host={$dbHost}",
'username' => "root",
'password' => "******",
'charset' => 'utf8'
];
$db = new /App/Library/DB();
$db->__setup($dbConf);
return $db;
};
// Define app routes
$app->get('/user/{uid}', 'App/Controller/IndexController:index');
IndexController类
namespace App/Controller;
class IndexController
{
protected $container;
public function __construct(ContainerInterface $container) {
$this->container = $container;
}
public function index($request, $response, $args) {
$info = $this->container['db']->fetch('SELECT name FROM user WHERE uid = :uid', [
'uid' => $args['uid']
]);
echo "user name is " . $info['name'];
}
}

IndexController类的是通过composer自动载入的(代码中没写):


"autoload": {
"psr-4": {
"App//": "app/"
}
},

代码中可以发现, 依赖容器 的注入是在 类实例化 的时候发生的。执行IndexController的index方法时,我们从$container中取出的db依赖,这时候,注册的回调函数被调用,返回实例。因为是用到时才实例化,这个叫做 延迟实例化 。


结合Swoole

Swoole 让PHP可以常驻内存,而且它提供了Http Server的功能,所以Slim和Swoole没什么冲突。


思考

Slim是通过当前路由(譬如/user/2,不带查询字符串)和http方法来找到正确的回调函数的。这些量Slim是从哪里取的呢?肯定是 $_SERVER 。查看slim源码:


run()方法:


public function run($silent = false)
{
$response = $this->container->get('response');
try {
ob_start();
$response = $this->process($this->container->get('request'), $response);
} catch (InvalidMethodException $e) {
$response = $this->processInvalidMethod($e->getRequest(), $response);
} finally {
$output = ob_get_clean();
}
if (!empty($output) && $response->getBody()->isWritable()) {
$outputBuffering = $this->container->get('settings')['outputBuffering'];
if ($outputBuffering === 'prepend') {
// prepend output buffer content
$body = new Http/Body(fopen('php://temp', 'r+'));
$body->write($output . $response->getBody());
$response = $response->withBody($body);
} elseif ($outputBuffering === 'append') {
// append output buffer content
$response->getBody()->write($output);
}
}
$response = $this->finalize($response);
if (!$silent) {
$this->respond($response);
}
return $response;
}

发现$request对象是从容器取出来的,那$request是怎么注册的呢??,那就看App类的构造函数了,最后发现Container类的构造函数中有 registerDefaultServices() 方法:


private function registerDefaultServices($userSettings)
{
$defaultSettings = $this->defaultSettings;
/**
* This service MUST return an array or an
* instance of /ArrayAccess.
*
* @return array|/ArrayAccess
*/
$this['settings'] = function () use ($userSettings, $defaultSettings) {
return new Collection(array_merge($defaultSettings, $userSettings));
};
$defaultProvider = new DefaultServicesProvider();
$defaultProvider->register($this);
}

查看$defaultProvider->register()方法:


public function register($container)
{
if (!isset($container['environment'])) {
/**
* This service MUST return a shared instance
* of /Slim/Interfaces/Http/EnvironmentInterface.
*
* @return EnvironmentInterface
*/
$container['environment'] = function () {
return new Environment($_SERVER);
};
}
if (!isset($container['request'])) {
/**
* PSR-7 Request object
*
* @param Container $container
*
* @return ServerRequestInterface
*/
$container['request'] = function ($container) {
return Request::createFromEnvironment($container->get('environment'));
};
}
//...

可以看到$request对象是通过Request::createFromEnvironment方法构造的,它需要从容器中取出 environment 依赖,而 environment 依赖是通过构造一个Environment对象得来的,它正好放入了 $_SERVER
查看Environment类源码,可以发现它继承了 Collection 类, Collection 的构造函数如下:


public function __construct(array $items = [])
{
$this->replace($items);
}

从上面我们可以得出,我们主要注册一个自定义的 environment 依赖就行,原来 $_SERVER 的信息可以从swoole的 $request->server 中取。


简单实现

server.php


<?php
use Slim/Http/Environment;
// 定义常量
define("ROOT", getcwd() . '/..');
define('APP', ROOT . '/app');
require ROOT . '/vendor/autoload.php';
// load functions
require APP . '/functions.php';
$http = new swoole_http_server("0.0.0.0", 8888);
$http->on("start", function ($server) {
echo "Swoole http server is started at http://0.0.0.0:8888/n";
});
$http->on("request", function ($request, $response) {
// Instantiate the app
$config = [
'settings' => [
'addContentLengthHeader' => false,
]
];
$config['environment'] = function () use($request) {
$server = [];
foreach ($request->server as $key => $value) {
$server[strtoupper($key)] = $value;
}
return new Environment($server);
};
$app = new /Slim/App($config);
// Register routes
require APP . '/routes.php';
// Run app
$slimResponse = $app->run(true);
$headers = $slimResponse->getHeaders();
foreach ($headers as $name => $values) {
$response->header($name, implode(", ", $values));
}
$response->header("X-Powered-By", "Salamander");
$response->end($slimResponse->getBody());
});
$http->start();

注意 $request->server中key都是小写的 ,所以这里转化了一下。


routes.php(在App目录中)


<?php
use /Psr/Http/Message/ServerRequestInterface as Request;
use /Psr/Http/Message/ResponseInterface as Response;
$app->get('/', function (Request $request, Response $response) {
$response->getBody()->write('Hello Salamander');
return $response;
});
$app->get('/user/{uid}', function (Request $request, Response $response, $args) {
$response->getBody()->write('Hello User:' . $args['uid']);
return $response;
});
测试
访问/


访问/user/45


打包下载测试

百度云盘


tip:环境基于docker的,运行 docker-compose up 即可


最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台