unoh.github.com

意外と身近なphar - PHp ARchive

Sun Dec 23 19:40:09 -0800 2007

こんにちは。shimookaです。

今回は意外と古くて身近、でも意外と知られていないphar(PHp ARchive)を取り上げてみました。

pharとは?

pharとはPHp ARchiveの略で、その名の通りPHPスクリプトのアーカイブです。含まれる内容はPHPスクリプトである必要はなく、複数のファイルを含めることができます。Javaの世界で言うjarに近いもので、拡張子は「.phar」となることが一般的です。

pharの特徴としては、以下のものが上げられます。

pharの中身と使い道

pharファイルは大まかには、データとスタブ、マニフェスト(アーカイブの情報を格納したバイナリデータ)で構成されます。前述のアーカイブに含まれるファイルはデータとして保存されています。スタブは、含まれているデータを処理するためのスクリプトのかたまりです。これをうまく使うことで、インストーラを作ることができます。つまり、

という構成ということです。Windows版のPHPに付属している「go-pear.phar」という3MBほどのファイルがあります。これをテキストエディタなどで開くと文字化けしているように見えますが、別に文字化けしている訳ではなく、マニフェストの部分が「文字化けしたように見え」ているだけです。

逆に、「何もしない」スタブを用意することで、純粋なアーカイブになります。

pharファイルを作ってみる

では、phar拡張モジュール使ってpharアーカイブを作ってみます。phar拡張モジュールはPHP5.2.0以降が必要で、2007/12/23時点の最新版はphar1.2.3です。

UNIX系OSの場合、インストールはpeclコマンドでOKです。インストール後、php.iniにextensionディレクティブを追加しておきます。

$ sudo pecl install phar
$ sudo echo "extension=phar.so" >> /path/to/php.ini

今回はクラスを定義した3つのPHPスクリプトを1つのpharにまとめてみます。インストーラではない純粋なアーカイブです。まずは、クラスを定義したファイルは以下の通りです。

Foo.class.php

<?php
class Foo
{
    public function getName() {
        return __CLASS__;
    }
    public function execute() {
        return 'This is ' . $this->getName();
    }
}

Bar.class.php

<?php
class Bar
{
    public function getName() {
        return __CLASS__;
    }
    public function execute() {
        return 'This is ' . $this->getName();
    }
}

Hello.class.php

<?php
class Hello
{
    public function getName() {
        return __CLASS__;
    }
    public function greet() {
        return 'Hello, world!';
    }
}

次に、上記3ファイルを1つのphar(test.phar)にまとめるPHPスクリプトですが、簡単な以下のようになります。

create_phar.php

<?php
$files = array('Foo.class.php', 'Bar.class.php', 'Hello.class.php');

// pharインスタンスを生成
$phar = new Phar(dirname(__FILE__) . '/test.phar', 0, 'test.phar');

// ファイルをアーカイブに追加
foreach ($files as $filename) {
    $phar[$filename] = file_get_contents($filename);
}

echo "created\n";

実行結果は次の通りで、pharを作成する際にphp.iniの設定「phar.readonly」が0である必要があります。

$ php -d phar.readonly=0 create_phar.php
created
$ ls test.phar
test.phar
$

また、phar拡張モジュールはストリームラッパーも提供しています。pharストリームラッパーを使う場合は以下の通りです。

create_phar_wrapper.php

<?php
$files = array('Foo.class.php', 'Bar.class.php', 'Hello.class.php');

// ファイルをアーカイブに追加
foreach ($files as $filename) {
    file_put_contents(
        'phar://test2.phar/' . $filename,
        file_get_contents($filename));

}

echo "created\n";

作成されたtest.pharを利用する側のコードですが、以下のような感じです。require/includeする際にpharストリームラッパーを使って、アーカイブされたファイルを指定します。

test_phar_client.php

<?php
// pharに含まれるファイルを取り出す
require_once 'phar://test.phar/Foo.class.php';
require_once 'phar://test.phar/Hello.class.php';

$foo = new Foo();
echo $foo->execute() . "\n";

$greet = new Hello();
echo $greet->greet() . "\n";

実行すると、以下のようになります。

$ php test_phar_client.php
This is Foo
Hello, world!
$ 

まとめ

ざっとですがpharについて紹介してみました。

PHPには発音の仕方が分からない名前のものが多いですが、「phar」はどう発音するんでしょうか。。。これが一番の問題点かも知れません。

phar拡張モジュールは、「PHP5.3でcoreに入れたいよ」とか「次期PEARであるPEAR2で使われるかも」とか、不確定ですがいろいろと情報がありますので、今後pharを見る機会が増えるのではないかと思います。

個人的にはもうちょっと深堀りしてみたいと思っていますので、この続きはDo You PHP?で;-)