目次


PHP V5.3 では何が新しいのか

第 4 回 : Phar アーカイブを作成し、使用する

Comments

コンテンツシリーズ

このコンテンツは全#シリーズのパート#です: PHP V5.3 では何が新しいのか

このシリーズの続きに乞うご期待。

このコンテンツはシリーズの一部分です:PHP V5.3 では何が新しいのか

このシリーズの続きに乞うご期待。

Phar アーカイブの概念は Java™ 技術の JAR アーカイブに由来します。JAR アーカイブを利用すると、アプリケーションを 1 つのファイルの中にパッケージ化し、そのアプリケーションの実行に必要なものをすべてそのパッケージに含めることができます。しかし JAR アーカイブは (通常は C などの言語で作成される) 単一の実行形式ファイルの概念とは異なります。アーカイブ・ファイルは本当にアーカイブであり、アプリケーションをコンパイルしたものではないからです。つまり JAR ファイルはアプリケーションを構成するファイル群を実際に含んでいますが、セキュリティー上の理由から、内容はわからないようになっています。Phar 拡張モジュールも JAR と似た概念に基づいていますが、PHP の Web 環境に適するように設計されています。また、JAR アーカイブとは異なり、Phar アーカイブは PHP そのもので処理することができ、Phar アーカイブの作成、使用のために外部のツールは必要ありません。

Phar 拡張モジュールは PHP にとってまったく新しいものではありません。Phar 拡張モジュールは当初 PHP で作成され、PHP_Archive として知られていました。そして、2005年に PEAR リポジトリーに追加されましたが、Phar アーカイブに対する純粋な PHP のソリューションは実際には非常に動作が遅かったため、純粋な C による拡張モジュールとして 2007年に作り直されました。それと同時に、Phar アーカイブに対して繰り返し処理を行えるように、SPL の ArrayAccess オブジェクトを使うためのサポートが追加されました。それ以来、Phar アーカイブのパフォーマンスを改善するためにさまざまなことが行われてきました。

Phar を作成する

Phar ファイルを作成するためには、いくつかのステップが必要ですが、Phar アーカイブを作成するためのスタンドアロンのツールは存在しないため、どのステップにも何らかの形式の PHP コマンドが必要になります。また、Phar ファイルを作成したり、変更したりするには、php.ini の phar.readonly の値を 0 に設定する必要があります。PHP の中の Phar アーカイブの中でファイルを開いたり、参照したりするだけであれば、このような設定をする必要はありません。

では、あるアプリケーションを実行するために使用できる Phar アーカイブを作成する上で必要なステップを調べてみましょう。このアプリケーションは Web ブラウザーまたはコマンド・プロンプトから直接ロードするように設計されています。最初のステップは Phar ファイルを作成することです。そのためには、この例での作業対象となる Phar オブジェクトを作成します (リスト 1)。このオブジェクトを参照することによって Phar アーカイブのすべての側面を制御することができます。

リスト 1. Phar オブジェクトを作成する
$p = new Phar('/path/to/my.phar', CURRENT_AS_FILEINFO | KEY_AS_FILENAME, 'my.phar');
$p->startBuffering();

このコンストラクターの 1 番目のパラメーターは、Phar ファイルを保存する場所のパスです。2 番目のパラメーターは、この 2 番目のパラメーターに指定されたものすべてを RecursiveDirectoryIterator 親クラスに渡します。3 番目のパラメーターは、この Phar アーカイブをストリーム・コンテキストでどう呼ぶかを指定するエイリアスです。つまりリスト 1 の場合、この Phar の中にあるファイルを phar://my.phar と指定することで参照することができます。また Phar::startBuffering() メソッド呼び出しを実行してから、Phar::stopBuffering() を実行するまでにアーカイブに加えられた変更をバッファーすることもできます。必ずしも変更内容をバッファーする必要はありませんが、こうすることでスクリプトの中でアーカイブが変更されるたびにその変更を保存する必要がなくなるため、アーカイブを作成する際や変更する際のパフォーマンスを改善することができます。

作成される Phar は、デフォルトで、ネイティブな Phar ベースのアーカイブ・フォーマットを使います。また、Phar ファイルに ZIP フォーマットまたは TAR フォーマットを使うこともできます (そのためには Phar ファイルを ZIP フォーマットまたは TAR フォーマットに変換します)。リスト 2 はフォーマットを ZIP に変更した例です。

リスト2. ストレージ・フォーマットを ZIP に変更する
$p = $p->convertToExecutable(Phar::ZIP);

アーカイブ・フォーマットを変更することには利点と欠点があります。主な利点は ZIP ファイルや TAR ファイルを扱うための任意のツールを使ってアーカイブの内容を調べられることです。しかし使用する Phar アーカイブが、ネイティブな Phar ベースのアーカイブ・フォーマットを使っていない場合、アーカイブのロードに Phar 拡張モジュールを使う必要はありませんが、ZIP フォーマットや TAR フォーマットの Phar アーカイブの場合には Phar 拡張モジュールを使う必要があります。

次に、ファイル・スタブを定義する必要があります。ファイル・スタブは Phar ファイルがロードされると最初に呼び出されるコードです。

Phar ファイル・スタブ

ファイル・スタブは Phar ファイルがロードされると最初に実行される簡単なコード・セグメントにすぎず、必ず __HALT_COMPILER() トークンで終了します。リスト 3 は典型的なファイル・スタブの例を示しています。

リスト 3. Phar ファイル・スタブ
<?php
Phar::mapPhar();
include 'phar://myphar.phar/index.php';
__HALT_COMPILER();

上記の Phar::mapPhar() メソッド呼び出しはマニフェストを読み取ることで Phar アーカイブを初期化します。Phar アーカイブの初期化は、アーカイブの中で phar:// ストリーム・ラッパーを使ってファイルを参照する前に行う必要があります。最初にロードするファイルはアプリケーションで通常最初にロードされるファイル (この例では index.php) です。

このスタブを Phar アーカイブに追加する方法は、使用するアーカイブ・フォーマットに依存します。Phar ベースのアーカイブの場合には Phar::setStub() メソッドを使います。このメソッドは唯一のパラメーターとして PHP コードを受け付け、ストリングとしてスタブに配置します。リスト 4 はこの方法を示しています。

リスト 4. Phar::setStub() を使ってファイル・スタブを作成する
$p->setStub('<?php Phar::mapPhar(); 
include 'phar://myphar.phar/index.php'; __HALT_COMPILER(); ?>');

index.php ページにリダイレクトする以外にスタブをほとんど使わない場合には、ヘルパー・メソッド Phar::createDefaultStub() を使ってファイル・スタブを作成させることができます。そのためには、ファイル・スタブの中に含めたいファイル名を渡せばよいだけです。リスト 5 では Phar::setStub() メソッド呼び出しを作り直し、このヘルパー・メソッドを使うようにしています。

リスト 5. Phar::createDefaultStub() を使ってファイル・スタブを作成する
$p->setStub($p-> createDefaultStub('index.php'));

Phar::createDefaultStub() メソッドの 2 番目のオプション引数を使うと、Web サーバーから Phar がロードされた場合に別のファイルを含めることができます。これはアプリケーションがコマンドラインや Web ブラウザーのコンテキストで使われるように設計されている場合に便利です。

ZIP ベースの実装や TAR ベースの実装では、setStub() コマンドを使う代わりに上記のスタブの内容を .phar/stub.php ファイルの中に保存します。

アーカイブにファイルを追加する

Phar オブジェクトは ArrayAccess という SPL オブジェクトを使うことによって、アーカイブの中身へのアクセスを、配列を使用して行えるようになっています。このため、さまざまな方法でアーカイブにファイルを追加することができます。最も容易な方法は ArrayAccess インターフェースを直接使う方法です。

リスト 6. アーカイブにファイルを追加する
$p['file.txt'] = 'This is a text file';
$p['index.php'] = file_get_contents('index.php');

リスト 6 では、ファイル名が配列のキーとして指定され、ファイルの中身が値として指定されています。file_get_contents() 関数を使うと既存のファイルの中身を取得して値として設定することができます。これによってアーカイブにファイルを追加する方法が多少柔軟になり、既存のファイルを参照するか、その場でファイルを作成するか、いずれかの方法を選択できるのです。後者の方法をアプリケーションのビルド・スクリプトの一部として利用すると便利です。

Phar アーカイブに保存するファイルのサイズが大きい場合には、オプションとしてアーカイブの中でファイルを圧縮することができます。そのためには PharFileInfo::setCompressedGZ() メソッドによる gzip 圧縮または PharFileInfo::setCompressedBZIP2() メソッドによる bzip2 圧縮を使います。リスト 7 では bzip2 を使ってファイルを圧縮します。

リスト 7. bzip2 を使って Phar アーカイブの中でファイルを圧縮する
$p['big.txt'] = 'This is a big text file';
$p['big.txt']->setCompressedBZIP2();

ファイルを圧縮するため、あるいは中に圧縮ファイルを含むアーカイブを使うためには、PHP インストールの中で bzip2 拡張モジュールまたは (gz 圧縮ファイルの場合には) zlib拡張モジュールを有効にする必要があります。

例えば、アーカイブに追加するファイルが大量にあるとしましょう。その 1 つ 1 つを ArrayAccess インターフェースを使って追加するのは面倒なので、そのためのショートカットがいくつかあります。1 つの方法は Phar::buildFromDirectory() メソッドを使う方法です。このメソッドは指定されたディレクトリーをウォークスルーし、そのディレクトリーの中にあるファイルを追加します。またこのメソッドは追加するファイルをフィルタリングすることもできます (2 番目のパラメーターとしてファイルの正規表現パターンを渡し、突き合わせを行ってアーカイブに追加します)。リスト 8 はこのメソッドの使い方を示しています。

リスト 8. Phar::buildFromDirectory() を使ってアーカイブにファイルを追加する
$p->buildFromDirectory('/path/to/files','./\.php$/');

リスト 8 は指定されたディレクトリーの中にあるすべての PHP ファイルを Phar アーカイブに追加します。追加されたファイルに後で何らかの変更を加える必要がある場合には (例えば追加されたファイルを圧縮するように設定するなど)、改めて ArrayAccess インターフェースを使うこともできます。

また、Phar::buildFromIterator() メソッドによるイテレーターを使ってファイルを追加することもできます。2 つのタイプのイテレーターがサポートされており、1 つのイテレーターは Phar 内のファイル名をディスク上のファイルの名前にマッピングし、もう 1 つのイテレーターは SplFileInfo オブジェクトを返します。そうしたイテレーターと互換性があるイテレーターの 1 つが RecursiveDirectoryIterator です。このイテレーターを使ってディレクトリーの中にあるファイルをアーカイブに追加する方法が下記リスト 9に示してあります。

リスト 9. Phar::buildFromIterator() を使ってアーカイブにファイルを追加する
$p->buildFromIterator(new RecursiveIteratorIterator
(new RecursiveDirectoryIterator('/path/to/files')),'/path/to/files');

Phar::buildFromIterator() メソッドはイテレーター・オブジェクト自体を唯一の引数として受け付けます。上記の例では RecursiveDirectoryIterator オブジェクトを RecursiveIteratorIterator オブジェクトでラップしており、RecursiveIteratorIterator オブジェクトは Phar::buildFromIterator() が必要とするイテレーターと互換性のあるイテレーターを提供します。

これで PHP アプリケーションで使用できる Phar アーカイブを作成することができました。では、このアーカイブがいかに手軽に使えるかを説明しましょう。

Phar アーカイブを扱う

Phar アーカイブの良い点は、どのようなアプリケーションにも容易に統合できる点です。ネイティブな Phar ベースのアーカイブ・フォーマットを使った場合には、この利点が特によくわかります。この場合には PHP がそのままファイルをロードしてその中身を抽出できるため、Phar 拡張モジュールをインストールする必要すらありません。ZIP ベースのアーカイブや TAR ベースのアーカイブの場合には Phar 拡張モジュールをロードする必要があります。

Phar アーカイブは通常の任意の PHP ファイルの場合とまったく同じように、アプリケーションの中に含められるように設計されています。そのため、他のサードパーティー・コードを含めることに慣れているアプリケーション開発者にとっては Phar アーカイブの使い方はとても簡単です。では Phar をアプリケーションの中に統合することがどれほど容易かを調べてみましょう。

Phar アーカイブ・コードをアプリケーションの中に統合する

Phar アーカイブのコードを統合するための最も容易な方法は、単に Phar アーカイブを読み込み、使いたいファイルをその Phar ファイルの中に含める方法です。ロードされた Phar アーカイブ内部のファイルに対して phar:// ストリーム・ラッパーを使ってアクセスする方法を示したものが下記リスト 10 です。

リスト 10. Phar アーカイブにコードをロードする
include 'myphar.phar';  
include 'phar://myphar.phar/file.php';

最初の include によって、ファイル・スタブで指定されたコードを含めて myphar.phar アーカイブがロードされます。2 番目の include はストリーム・ラッパーを使って Phar アーカイブを開き、アーカイブの中の指定されたファイルのみを読み込みます。アーカイブ内のファイルを読み込む前に Phar アーカイブ自体を読み込む必要がないことに注意してください (リスト 10)。

Phar アーカイブから PHP アプリケーションを実行する

Phar アーカイブによって実現できる便利なことの 1 つが、アプリケーション全体を Phar アーカイブによってパッケージ化し、パッケージとしてアプリケーションを配布できることです。この方法の利点は、アプリケーションのデプロイメントが容易になることで、それによってパフォーマンスが犠牲になることもありません。これは PHP V5.3 で Phar に加えられたいくつかの機能強化のおかげです。しかし Phar 内部で実行するようにアプリケーションを設計する場合には、アプリケーションの設計に関して以下のようにいくつかの点を考慮する必要があります。

  1. アプリケーションのインスタンスに特有のファイル (構成ファイルなど) を作成する必要がある場合には、そうしたファイルをアーカイブの一部にすることはできません。そのため、そうしたファイルをアクセス可能な別の場所に書き出す必要があります。アプリケーションがその実行の一環としてキャッシュ・ファイルを作成する場合も同様です。
  2. 移植性を最大限に高めるためには、アーカイブの中でファイルを圧縮せず、Phar ベースのアーカイブ・フォーマットを使用する必要があります。ZIP ベースのアーカイブや TAR ベースのアーカイブの場合には PHP に Phar 拡張モジュールをインストールする必要がありますが、Phar ベースのアーカイブは Phar 拡張モジュールがインストールされていない場合でも使用することができます。
  3. アプリケーションの中のファイルを参照している場合には、その参照を変更し、アーカイブの名前を持つ phar:// ストリーム・ラッパーを使うようにする必要があります。これはこの前のセクションで説明したとおりです。

PHPMyAdmin は Phar の中にパッケージ化されており、Phar アーカイブの使い方がいかに容易かを示す例としてよく使われる PHP アプリケーションです (「参考文献」を参照)。PHPMyAdmin は完全に Phar アーカイブ・ファイルから実行するように設計されていますが、それでも構成ファイルを Phar アーカイブの外部に保存する機能を備えています。

まとめ

Phar アーカイブは PHP V5.3 に追加されたかなり便利な機能です。Phar アーカイブを利用するとアーカイブの中に PHP コードをパッケージ化することができるため、アプリケーションやライブラリーを 1 つのファイルとして配布する際に便利です。Phar アーカイブは require 関数または include 関数を使って PHP ファイルから容易にロードすることができ、また Phar アーカイブの名前を指定することによってブラウザーやコマンドラインから直接実行することもできます。


ダウンロード可能なリソース


関連トピック

  • PHP V5 マイグレーション・ガイド」を読み、PHP V4 で開発されたコードを V5 にマイグレートする方法を学んでください。
  • Connecting PHP Applications to Apache Derby」には Windows® に PHP をインストールして構成するための方法が解説されています (一部のステップは Linux® にも当てはまります)。
  • PHP でのプログラミングを学ぶための developerWorks のチュートリアル・シリーズとして、「Learning PHP, Part 1」、「Part 2」、「Part 3」を読んでください。
  • PHP.net には PHP 開発者のためのリソースが集まっています。
  • Recommended PHP reading list」を調べてみてください。
  • developerWorks には他にも PHP に関する資料が豊富に用意されています。
  • IBM developerWorks の PHP project resources を利用して PHP のスキルを磨いてください。
  • PHP でデータベースを使うのであれば、Zend Core for IBM を調べてみてください。これはシームレスでそのまま使用でき、インストールも容易な、IBM DB2 V9 をサポートする PHP の開発環境であり本番環境でもあります。
  • PHPMyAdmin は Phar の中にパッケージ化されており、Phar アーカイブの使い方がいかに容易かを示す例としてよく使われる PHP アプリケーションです。
  • PHP V5.2.6 を入手してください。

コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source
ArticleID=372815
ArticleTitle=PHP V5.3 では何が新しいのか: 第 4 回 : Phar アーカイブを作成し、使用する
publish-date=01272009