わぁいPhar、あかりPhar作るの大好き!

2012年はpharの年!嘘です!

みなさん、プログラムソースが1ファイルになってるの好きですか!

好きですよね!
http://www.google.co.jp/search?ie=UTF-8&q=phpspot+1%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB
ファイルの総行数が1万行超えても?

、、、ということで、PHPのためのアーカイブ形式pharについてです。
http://php.net/phar

ここ最近はpharとして提供されるものがいくつか出てきましたね!

  • pyrus.phar
  • imagine.phar
  • goutte.phar
  • guzzle.phar

また、Zend Framework 2 (http://packages.zendframework.com/) では

$pyrus download Zend_**

で、pharファイルとしてダウンロードできます。

PHP界隈での大きな流れとしてPHPUnitが3.6で下位互換性の問題が浮上したこともあり、
phpunit.phar作成についてSebastian Bergmanも前向きな姿勢がみえます。まさにpharのビッグウェーブ!といった所ですが、shimookaさんのphar紹介記事 意外と身近なphar - PHp ARchive から4年以上経ってます。そう、この記事は人類には早すぎたんだ!

(【※2016年7月追記】 上記Unohラボの過去記事は https://unoh.github.io/2007/12/24/phar_php_archive.html にて確認ください )


基本的なpharアーカイブの作成方法はマニュアルにある通りです。・・・って書こうと思ってたらこうだよ!

そのうちにきちんと書きます。

http://www.php.net/manual/ja/phar.creating.intro.php

めちゃんこ端的なサンプルとしての作成コードは

<?php
$phar = new Phar('hello.phar', 0, 'hello.phar');
$phar->addFromString('hello.php', '<?php echo "hello";');
$phar->setStub("<?php Phar::mapPhar(); __HALT_COMPILER();");

( マニュアルの"buildFromIterator""TwigをPhar化"のbuildFromDirectoryの記事も参照してみてください)

とにかく

などをアーカイブ作成する際に考慮しておきたい基本事項です。

んで、2、3のファイルなら明示的に追加対象にすればいいのですが、

  • ディレクトリまるごとやる場合(".svn"などのignoreファイルの考慮、strip_whitspace)
  • 依存するライブラリがある場合

などちょっとややこしいですね!

GoutteやBehatは独自にCompilerクラスを作ってpharコンパイルを行っています。
そのソースを見たところだと定型処理としてツールができそうだし、ありそうですね!


pharアーカイブ作成・展開を対象としたツールはいくつかあります。

Imagineはphar-utilをguzzleはphingのタスクを使ってるようです。

このうちempireについてはPEARの開発者@hことHelgi Þormar ÞorbjörnssonのPHP Beneluxスライドで知りました。


pyrusでのpharの作成はこのような形で実現できます。

$pyrus generate-pear2 Foo __uri
$pyrus make
$pyrus package -p

上記のコマンドのうちpackage -p
はphar作成オプションでのパッケージングコマンドで、phpの設定でphar.readonly=0でなくてはだめなので、一般には

$php -d phar.readonly=0 pyrus package -p

です。
(補足として、phar作成の記事やライブラリのエラーメッセージでphp.ini変えろとか言ってきますが、上記のようにディレクティブ設定してればいいでないのん?)

あなたが単にPSR-0に沿ったライブラリ用ソースを持っていれば、上記generate-pear2で作ったひな形フォルダのsrcにファイルをぶち込めばphar作成可能です。

デフォルトのstubの方でspl_autoload_registerが作成されているので、作成されたphar形式のライブラリの使用は、

<?php require_once 'Foo-0.1.0.phar';

となります。

また、この pyrus package -p で作成したpharファイルは、PEARだと、*.tgzでおなじみだったPEARパッケージアーカイブ形式でもあるようで、

pyrus install Foo.phar

でそのままインストールも可能です。

作成するpharが依存するファイルやPEARパッケージの中身加えるにはどうすればいいの?

作成対象のpharが何かしらの依存ファイルがある場合、extrasetup.phpに個別のファイルやpearパッケージを指定することで、依存ファイルをひっくるめたpharパッケージを作成可能です。

<?php
// レジストリ内にあるパッケージを参照する場合
$config = \Pyrus\Config::singleton(__DIR__ . '/vendor');

$extrafiles = array(
    $config->registry->toPackage('PEAR2_HTTP_Request', 'pear2.php.net'),
);

// 直接チェックアウト先のpackage.xmlを参照する場合
$extrafiles = array(
  new \PEAR2\Pyrus\Package(__DIR__ . '/../../HTTP_Request/trunk/package.xml'),
);

// 個別に特定のファイルを指定する場合
$extrafiles = array(
    'php/PEAR2/HTTP/Request.php' => __DIR__ . '/Request.php',

http://pear.php.net/manual/ja/pyrus.commands.package.php

extrasetup.phpに記述した依存情報はpackage.xmlにはwriteされません。

ただし、今のところの不具合としてgenerate-pear2で対象としてるひな形でのフォルダ"scripts"、"tests"、"data"が存在した場合、makeで不整合のあるpackage.xmlが作成されるようで、インストールに失敗します。んがんぐ。
pyrus/Pyrus_Developer#14
pyrus/Pyrus#26

*1:リポジトリのホームURLが http://blog.kotowicz.net/2010/08/hardening-php-how-to-securely-include.html になってる通りphar作成のセキュリティ目的が主なようですが、--nsオプションで証明書なしで作成できます