Phalcon でモダンなアプリケーションを開発するために

Phalcon

Phalcon は数ある PHP のフレームワークの中でも最も高速なフレームワークです。弊社では、いくつかのサービスでこのフレームワークを利用して開発を行っています。

Phalcon は Ruby on Rails にあるような「設定より規約」のようなソフトウェア設計パラダイムに基づいていないため、開発者自身が多くのことを決定しなくてはなりませんが、その代償として自由に設計やアーキテクチャを決定することが出来ます。

今回は、 Phalcon を利用してよりモダンなアプリケーションを開発するための基本となるポイントをご紹介したいと思います。

前提

今回利用を想定したソフトウェアのバージョンは以下の通りです。特に Phalcon は、今後リリースが予定されているバージョン 4 以降で大きく異なる可能性がありますので、ご注意ください。

  • PHP 7.1.x
  • Phalcon 3.3.x

ディレクトリ名をパスカルケースにする

Phalcon アプリケーションの開発を開始する際、多くの開発者は Phalcon Devtools を利用してアプリケーションのひな型 (skeleton) を生成するかと思います。生成したひな型では、ディレクトリ名が小文字になってしまっていますので、まずはパスカルケースに変更し、 PSR-4 に対応しましょう。

以下は Skeleton Single を利用したアプリケーションのディレクトリ名を変更した例です。

myapp/
  app/
    Config/
    Controllers/
    Views/
  public/
    .htaccess
    index.php

Composer Autoloader を利用する

Phalcon は Phalcon\Loader クラスによるオートロードの機能を提供します。 Phalcon のチュートリアルでは、この機能を利用することが前提で書かれていますが、多くのアプリケーションでは Composer を利用して、様々なライブラリを利用するかと思います。

Composer を利用する場合には、オートロードの仕組みは Composer に任せてしまって問題ありません。適切に最適化を行えば、 Composer Autoloader は Phalcon\Loader に劣らないパフォーマンスを発揮します。 Composer の最適化については、Autoload Optimization – Composer を参照してください。

Phalcon アプリケーションで Composer Autoloader を利用するのはとても簡単です。まずは composer.json に以下の記述を追加します。

  "autoload": {
    "psr-4": {
      "MyApp\\": "app/"
    }
  },

次に、 public/index.php の記述を変更します。

    /**
     * Include loader
     */
    // require __DIR__ . '/../app/config/loader.php';
    include __DIR__ . '/../vendor/autoload.php';

名前空間を利用する

名前空間はクラス/関数/定数などの名前の衝突を回避するための機能です。Composer で利用されるオートロードの規約を定めた PSR-4 でも利用を強制しています。
Phalcon のコントローラで名前空間を利用するためには、 Router の設定は以下のように記述する必要があります。

<?php

$router->add(
    "/hello",
    [
        "namespace"  => "MyApp\\Controller",
        "controller" => "Hello",
        "action"     => "index",
    ]
);

コントローラの名前空間を予め設定することも可能です。

<?php

$router->setDefaultNamespace('MyApp\\Controller');
$router->add(
    "/hello",
    [
        "controller" => "Hello",
        "action"     => "index",
    ]
);

名前空間の利用についての詳細な情報は、 Working with Namespace をご参照ください。

コンストラクタインジェクションを利用する

Dependency Injection の方法はいくつかありますが、ここでは Phalcon でコンストラクタインジェクションを利用するための方法をご紹介します。

以下の SomeApp\SomeComponent クラスは Phalcon\Http\Response クラスに依存しています。

<?php

namespace SomeApp;

use Phalcon\Http\ResponseInterface;

class SomeComponent
{
    /**
     * @var Response
     */
    protected $response;

    public function __construct(ResponseInterface $response)
    {
        $this->response = $response;
    }
}

これを解決できるように、 Phalcon\Di オブジェクトにサービスとして SomeApp\SomeComponent クラスを登録します。

<?php

$di->set(
    'SomeApp\SomeComponent',
    [
        'className' => 'SomeApp\SomeComponent',
        'arguments' => [
            [
                'type' => 'service',
                'name' => 'Phalcon\Http\Response',
            ],
        ]
    ]
);

Phalcon\Di はサービスを取得する際に、そのサービスが事前に DI コンテナに登録されていないかを確認します。要求されたサービス名と同一の名称でサービスが登録されていれば、そのサービスを返却します。登録されていない場合にはサービス名と同一のクラスが存在するかを判定し、存在する場合には新しいインスタンスを生成して返します。

つまり、上記の設定で SomeApp\SomeComponent を要求すると、次のような処理が実行されます。

  1. SomeApp\SomeComponent が事前に DI コンテナに登録されているかを確認
  2. 登録されているので、 SomeApp\SomeComponent の引数となる Phalcon\Http\Response の解決を実行
  3. Phalcon\Http\Response が事前に DI コンテナに登録されているかを確認
  4. 登録されていないので、 Phalcon\Http\Response のインスタンスを生成して返却
  5. 生成した Phalcon\Http\Response インスタンスを引数に指定して SomeApp\SomeComponent のインスタンスを生成

Phalcon\Di は Phalcon の中でも重要な機能の一つです。ドキュメント を参照して是非マスターしましょう。

さらなる速さを求めて

Phalcon を利用することで高速化する部分は、フレームワークとしての機能の部分のみです。開発者が実装したソースコードや、データベースや API などの通信は、Phalcon を利用したからといって高速化できるものではありません。さらなる高速化を求めるのであれば、基本に立ち返り、以下のような点を改善していきましょう。

  • Composer Autoloader は最適化する
  • OPcache を利用する
  • DB や API の結果をキャッシュする
  • PHP のバージョンを更新する

おわりに

Phalcon は高速なフレームワークというだけでなく、フレームワーク内の各コンポーネントが疎結合であり、非常にシンプルなコードとなっていることも特徴の一つです。Phalcon が開発者に強制する規則が少ないので、自由なアーキテクチャを柔軟に取り入れることができます。弊社では多くのサービスで DDD (ドメイン駆動設計) や ADR (Action-Domain-Responder) などのアーキテクチャを採用しています。

本記事を読んでくださった方の中で、 Phalcon に興味があるけれど使ったことがない、という方がいらっしゃれば、是非一度利用してみてください。既に利用していらっしゃる方は、 Phalcon をどのように利用しているか、是非ご紹介ください。

参考

PHP Engineer who developed web sites with Phalcon