zend-expressiveに見るPSR-7時代のPHPフレームワーク
Zendによる新しいマイクロフレームワーク、zend-expressiveのバージョン1.0.0rc2がリリースされました。
今日は、このPSR-7対応のzend-expressiveをインストールしてみます。
zend-expressiveのインストール
最も簡単なインストール方法である、スケルトンプロジェクトをComposerでインストールする方法でインストールします。
$ composer create-project -s rc zendframework/zend-expressive-skeleton ze
ルータの選択
まず、以下のようにルータをどれにするか聞かれます。
Installing zendframework/zend-expressive-skeleton (1.0.0rc2)
- Installing zendframework/zend-expressive-skeleton (1.0.0rc2)
Loading from cache
Created project in ze
> App\Composer\OptionalPackages::install
Setup data and cache dir
Setting up optional packages
Which router you want to use?
[1] Aura.Router
[2] FastRoute
[3] Zend Router
Make your selection or type a composer package name and version (FastRoute):
デフォルトはFastRouteですが、Aura.RouterやZend Routerも選べます。
とりあえず、デフォルトのまま [return] キーを押して進みます。
Make your selection or type a composer package name and version (FastRoute):
- Adding package zendframework/zend-expressive-fastroute (^0.2)
- Copying /config/autoload/routes.global.php
zendframework/zend-expressive-fastrouteが追加されました。
DIコンテナの選択
続いてDIコンテナをどれにするか聞かれます。
Which container you want to use for dependency injection?
[1] Aura.Di
[2] Pimple-interop
[3] Zend ServiceManager
Make your selection or type a composer package name and version (Zend ServiceManager):
デフォルトはZend ServiceManagerですが、Aura.DiとPimple-interopが選べます。
デフォルトのまま [return] キーを押して進みます。
Make your selection or type a composer package name and version (Zend ServiceManager):
- Adding package zendframework/zend-servicemanager (^2.5)
- Adding package ocramius/proxy-manager (^1.0)
- Copying /config/container.php
zendframework/zend-servicemanagerなどが追加されました。
テンプレートエンジンの選択
次はテンプレートエンジンの選択です。
Which template engine you want to use?
[1] Plates
[2] Twig
[3] Zend View installs Zend ServiceManager
[n] None of the above
Make your selection or type a composer package name and version (n):
デフォルトはなしですが、Plates、Twig、Zend Viewが選択できます。
今回はデフォルトのなしにします。
エラーハンドラの選択
開発時に使用するエラーハンドラの選択です。
Which error handler do you want to use during development?
[1] Whoops
[n] None of the above
Make your selection or type a composer package name and version (Whoops):
Whoopsしか選択肢はないので、Whoopsにしておきます。
Make your selection or type a composer package name and version (Whoops):
- Adding package filp/whoops (^1.1)
- Copying /config/autoload/errorhandler.local.php
filp/whoopsが追加されました。
そして、パッケージのインストールが開始されます。
インストールされたパッケージは以下でした。
$ composer show -i
composer/composer 1.0.0-alpha10
container-interop/container-interop 1.1.0
doctrine/instantiator 1.0.5
filp/whoops 1.1.7
justinrainbow/json-schema 1.5.0
nikic/fast-route v0.6.0
ocramius/proxy-manager 1.0.2
phpdocumentor/reflection-docblock 2.0.4
phpspec/prophecy v1.5.0
phpunit/php-code-coverage 2.2.4
phpunit/php-file-iterator 1.4.1
phpunit/php-text-template 1.2.1
phpunit/php-timer 1.0.7
phpunit/php-token-stream 1.4.8
phpunit/phpunit 4.8.15
phpunit/phpunit-mock-objects 2.3.8
psr/http-message 1.0
roave/security-advisories dev-master 43ac5a3
sebastian/comparator 1.2.0
sebastian/diff 1.3.0
sebastian/environment 1.3.2
sebastian/exporter 1.2.1
sebastian/global-state 1.1.1
sebastian/recursion-context 1.0.1
sebastian/version 1.0.6
seld/jsonlint 1.3.1
squizlabs/php_codesniffer 2.3.4
symfony/console v2.7.5
symfony/finder v2.7.5
symfony/process v2.7.5
symfony/yaml v2.7.5
zendframework/zend-code 2.5.2
zendframework/zend-diactoros 1.1.4
zendframework/zend-escaper 2.5.1
zendframework/zend-eventmanager 2.5.2
zendframework/zend-expressive 1.0.0rc2
zendframework/zend-expressive-fastroute 0.2.0
zendframework/zend-hydrator 1.0.0
zendframework/zend-servicemanager 2.6.0
zendframework/zend-stdlib 2.7.4
zendframework/zend-stratigility 1.1.2
このようにzend-expressiveでは、ルータ、DIコンテナ、テンプレートエンジン、開発時のエラーハンドラが最初から選択可能になっています。
このフレームワークを使っているからルータはフレームワークに付属しているものしか使えないなどというバカバカしいことはありません。
Webサーバの起動
PHPビルトインWebサーバを起動してみましょう。
$ php -S 127.0.0.1:8080 -t public/
http://localhost:8080/
にブラウザでアクセスすると、以下のJSONを見ることができます。
{"welcome":"Congratulations! You have installed the zend-expressive skeleton application.","docsUrl":"zend-expressive.readthedocs.org"}
さて、この値はどこから来ているのでしょう?
ルーティング
ルーティングの設定は、以下にありました。
config/autoload/routes.global.php
<?php
return [
'dependencies' => [
'invokables' => [
Zend\Expressive\Router\RouterInterface::class => Zend\Expressive\Router\FastRouteRouter::class,
],
],
'routes' => [
[
'name' => 'home',
'path' => '/',
'middleware' => App\Action\HomePageAction::class,
'allowed_methods' => ['GET'],
],
[
'name' => 'api.ping',
'path' => '/api/ping',
'middleware' => App\Action\PingAction::class,
'allowed_methods' => ['GET'],
],
],
];
キーroutes
の最初の配列
[
'name' => 'home',
'path' => '/',
'middleware' => App\Action\HomePageAction::class,
'allowed_methods' => ['GET'],
],
がさきほどのJSON出力のルートです。クラス名がApp\Action\HomePageAction
であることがわかります。
アクション
App\Action\HomePageAction
クラスは以下にあります。
src/Action/HomePageAction.php
<?php
namespace App\Action;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Expressive\Router;
use Zend\Expressive\Template;
class HomePageAction
{
private $router;
private $template;
public function __construct(Router\RouterInterface $router, Template\TemplateRendererInterface $template = null)
{
$this->router = $router;
$this->template = $template;
}
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next = null)
{
$data = [];
if ($this->router instanceof Router\AuraRouter) {
$data['routerName'] = 'Aura.Router';
$data['routerDocs'] = 'http://auraphp.com/packages/Aura.Router/';
} elseif ($this->router instanceof Router\FastRouteRouter) {
$data['routerName'] = 'FastRoute';
$data['routerDocs'] = 'https://github.com/nikic/FastRoute';
} elseif ($this->router instanceof Router\ZendRouter) {
$data['routerName'] = 'Zend Router';
$data['routerDocs'] = 'http://framework.zend.com/manual/current/en/modules/zend.mvc.routing.html';
}
if ($this->template instanceof Template\PlatesRenderer) {
$data['templateName'] = 'Plates';
$data['templateDocs'] = 'http://platesphp.com/';
} elseif ($this->template instanceof Template\TwigRenderer) {
$data['templateName'] = 'Twig';
$data['templateDocs'] = 'http://twig.sensiolabs.org/documentation';
} elseif ($this->template instanceof Template\ZendViewRenderer) {
$data['templateName'] = 'Zend View';
$data['templateDocs'] = 'http://framework.zend.com/manual/current/en/modules/zend.view.quick-start.html';
}
if (!$this->template) {
return new JsonResponse([
'welcome' => 'Congratulations! You have installed the zend-expressive skeleton application.',
'docsUrl' => 'zend-expressive.readthedocs.org',
]);
}
return new HtmlResponse($this->template->render('app::home-page', $data));
}
}
__invoke()
メソッド内になんかごちゃごちゃif文がありますが、今はテンプレートエンジンがないので、結局以下のif文だけが実行されていることがわかります。
if (!$this->template) {
return new JsonResponse([
'welcome' => 'Congratulations! You have installed the zend-expressive skeleton application.',
'docsUrl' => 'zend-expressive.readthedocs.org',
]);
}
テンプレートエンジンをインストールした方がページの見栄えがよかったみたいですね。
まとめ
PHPはPSR-7時代に突入しました。フレームワークの抽象化、コンポーネント化はさらに進みます。すでにルータやDIコンテナさえもこのように組み替え可能です。
参考
Date: 2015/10/23