PHP
Phalcon
Zephir
PhalconDay 21

PHPを拡張する言語、Zephirについて

More than 1 year has passed since last update.

PHPはいかにして拡張されるか

PHPは従来、C言語で書かれたExtensionによって拡張されて来ました。
しかしPHPの開発者にとってCのハードルは高く、またCの開発者も明示的なメモリ管理に難儀してきました。
それを解決するのがZephirというPHP Extension開発専用の言語です。

PHPを拡張する言語、Zephirとは

http://zephir-lang.com/

Zephir(Zend Engine PHP Intermediate)は現在、Phalcon開発チームが並行して開発を進めている静的/動的言語です。
静的に変数型を宣言するのが標準的な記法ですが、型推論の機能を利用することも可能です。
2014年12月末現在での最新バージョンは0.5.7で、安定版に達していないものの、既に実用レベルのExtensionをPHPとほぼ変わらぬ記法で開発できるようになっています。

詳しくは以下の記事を参考にして下さい。
2つ目の記事には、ZephirでPHP標準関数を用いたExtensionを作るとデフォルトのPHPより高速に動作するという、興味深い事例も紹介されています。

Zephir使えばPHP Extensionが誰でも超絶簡単に作れる
PHPエクステンションが作れるZephirのコンパイラとコードの最適化の話

最新のZephirでExtensionを組んでみよう

上で紹介した記事の内容は現在でもほぼそのまま活用できるのですが、僅かに変更点が見つかりました。
それらを踏まえて最新ver0.5.7のZephirのインストールからExtensionの作成までをチュートリアルで追っていきたいと思います。
調査した環境はPHP5.5.20をインストール済みのCentOS 6.5です。

1. インストール

install
$ cd /usr/local/src
$ git clone https://github.com/phalcon/zephir

まずGithubのZephirリポジトリをcloneします。
そしてインストールを実行します。

$ cd zephir
$ ./install-json
$ ./install -c

ここでre2cというコマンドがインストールされていないという警告が出る場合があります。
その際はyumからre2cをインストールしてから再度Zephirのインストールをやり直してください。

$ yum install re2c

2. Zephirプロジェクトの生成

以下のコマンドで「test」という名前のExtensionのプロジェクトを立ち上げます。
ディレクトリはどこでも構いませんが、/usr/local/srcを推奨します。

$ zephir init test

内部構造はこんな感じになります。

[test]
 └ config.json
 └ [ext]
 └ [test]

config.jsonがZephirプロジェクトの設定ファイル、
extがZephirの作業ディレクトリ(C言語のコンパイルが行われる)、
プロジェクトと同じ名前のディレクトリがExtensionのソースを構築していく場所になります。
今回の場合はtest/testです。移動して作業を開始しましょう。

3. Zepファイルの構築

testディレクトリ内にExtensionの実体となる「Zep」ファイルを作成します。
拡張子を「.zep」とし、構築するクラス名とファイル名は合わせて下さい。

test.zep
namespace Test;

class Test
{
    public static function inArray(var needle, array arr)
    {
        return in_array(needle, arr);
    }
}

ソースコードはk-motoyanさんのものをお借りしています。

殆どPHPと変わらない記法で開発を進められることが分かると思います。
Zephir独特の記法については公式リファレンスを参考にしてください。

PHPと違って、Class外でのコードの記述は許されていません。
キャメルケースにしたプロジェクト名をNameSpaceとして1行目に指定し、Classをその下に構築していきます。

また変数の使用には必ず事前の宣言(初期化)が必要かつ、「$」は不要です。
初期化の際に型を記述しておくことで、厳格な型指定が可能になります。

PHP標準関数はZephir上でも問題なく使えます。
申し訳ないのですが、PHPのバージョンによる差は未検証です。
おそらくインストールされているPHPのバージョンに依存しています。
全てをオブジェクトとして扱う仕様であるため、string->length()のように、変数から生えるメソッドもあります。

4. Extensionをビルド

Zepファイルの編集を終えたら、一階層上(プロジェクトのルートディレクトリ)に戻ります。
そして以下のコマンドを実行することでC言語へのコンパイルとExtensionの作成が同時に行われます。

$ zephir build

Preparing for PHP compilation...
Preparing configuration file...
Compiling...
Installing...
Extension installed!
Add extension=test.so to your php.ini
Don't forget to restart your web server

これでExtensionの作成は完了です。
最新のZephirではtest.soが/usr/lib64/php/modules/に自動で配置されるので、php.iniに以下の記述を付け加えるだけOKです。

php.ini
[Test]
extension=test.so

php.iniの編集が終わったらWebサーバを再起動しましょう。
エラーが出なければExtensionはPHPに組み込まれています。早速動作確認に移りましょう!

5. 動作確認

test.php
$array = [1,2,3,4,5,6,7,8,9];

if (Test\Test::inArray(2, $array))
{
  echo 'OK';
}
else
{
  echo 'NG';
}
結果
OK

Zephirで作成したExtensionは、プロジェクト名\クラス名を指定することで実行できます。
関数の呼び出し規則はPHPと全く変わりません。
今回inArrayにはstaticとpublicを指定してあったので、Test\Testをインスタンス化してから呼び出すことも出来ます。

test.php
$test  = new Test\Test;
$array = [1,2,3,4,5,6,7,8,9];

if ($test->inArray(2, $array))
{
  echo 'OK';
}
else
{
  echo 'NG';
}

[応用] Zephirでオブジェクトの実装

Zephirで構築したクラスはPHPと同様の振る舞いをしてくれるので、以下のような実装も可能です。

variable.zep
namespace Test;

Class Variable
{
  protected a = 1;

  public function setVar(var a)
  {
    let this->a = a;
  }

  public function getVar()
  {
    return this->a;
  }
}

ビルドとWebサーバの再起動は忘れずに。

variable.php
$variable = new Test\Variable;
echo $variable->getVar();

$variable->setVar(100);
echo $variable->getVar();
結果
1
100

なぜ我々はZephirを使うのか?

Zephirはビルド時にC言語にコンパイルされます。
つまり、Zephirを用いるとPHPと非常に似た記法を保ちながら、C言語相当の実行速度を手に入れることが出来るのです。

またk-motoyanさんの記事にもあった話なのですが、Zephirは独自の最適化によって、Zepファイルに記述されたPHP標準関数をより高速な実装に置き換えることが出来ます。
GithubのZephirのリポジトリには、Optimizers(最適化)というディレクトリがあり、ここで定義されている関数については全て高速化が効くようになっている模様です。
ベンチマークは取っていないので確実ではありませんが、ここから呼び出されているzephir_fast_in_arrayがin_arrayの高速化を果たしているところから見てほぼ間違いないと思われます。

まとめ

・Zephirを使うとPHPに非常に似た記法でExtensionを構築できる
・ExtensionはC言語で実装されているため、実行速度の高速化が見込める
・Zephir上では一部のPHP標準関数がより高速な実装に置き換えられる

やったぜ。

最後に

Phalcon2.xはC言語で書かれていたPhalcon1.xのZephir実装として開発が進められています。
それは最初に書いた、「C言語に明るいPHPerが少ないため」という理由から来るものです。
正直自分も高専で習ったレベルなのでC言語に強いとは言えません。
それでもこのWeb時代は割と生きていけてしまうのです。

ZephirはそのようなPHPerの非常に心強い味方になってくれる言語です。
まだ安定版が出ていないため実装の荒さも散見されますが、実用レベルのExtensionを構築することは十分に可能です。
皆さんもPHPではどうしても解決できない速度問題にぶち当たったとき、このZephirを是非有効活用してください。

またPhalconも素晴らしいフレームワークです。
小さなシステムを立ち上げるときのMicro Applicationsのさっくり具合と実行速度は病み付きになります。
2015年にはより一層コミュニティが盛り上がってくれることを祈るばかりです。

では遅刻してしまって申し訳ありませんでした!
次の記事はnise_nabeさんの担当です!
宜しくお願い致します!

追記

現在Zephirプロジェクトでは開発資金の寄付を求めているようです。
詳細は以下からどうぞ。
http://blog.a-way-out.net/blog/2014/12/24/phalcon-funding-campaign/