PHP V5 は 2004年にリリースされましたが、PHP V4 が OOP (object-oriented programming: オブジェクト指向プログラミング) とその設計に関して提供していたものと比べると、非常に大きく飛躍しており、必要とされていた改善もいくつか行われました (例えばクラスの可視性や、適切なコンストラクターとデストラクター、タイプ・ヒンティング、クラス・リフレクション API など)。PHP V5 によって PHP での高度なオブジェクト指向プログラミングの扉が開かれ、多くのデザイン・パターンを今までよりもはるかに容易に実装できるようになり、またクラスや API の設計も改善されました。
PHP V5.3 では小さな追加が数多く行われたことにより、OOP が機能強化されています。そうした改善事項には、構文の追加やパフォーマンスの改善などがあります。まず最初に、静的なメソッドとメンバーに関する新機能を見てみましょう。
PHP V5 で追加された便利な機能の 1 つが、クラスのメソッドまたはメンバーを静的なものとして指定できる機能です (PHP V4 でもクラスのメソッドとメンバーへの静的アクセスをサポートしていましたが、メソッドまたはメンバーが静的アクセス用に設計されていることを指定できる機能はありませんでした)。静的なアクセスは (クラスのインスタンスが 1 つしか存在しない) シングルトンによるデザイン・パターンを実装する際に特に便利です。
PHP V5.3 では、クラス内にある静的なメソッドやメンバーのサポートを強化するためにいくつか機能が追加されています。まず、新たに追加されたマジック・メソッドである __callStatic() を見てみましょう。
PHP V5 には、クラス内で使用できる特別に定義されたメソッド (マジック・メソッドと呼ばれます) がいくつかあります。クラスの中でマジック・メソッドを定義すると、特別な機能を実現することができ、オーバーロード (メソッドが異なる型のパラメーターを受け付けられる機能) やポリモーフィズム (異なるデータ型が同じインターフェースを使用できる機能) が可能になります。またマジック・メソッドによって、さまざまなタイプの OOP プログラミング手法やデザイン・パターンを PHP で容易に使えるようになります。
PHP V5.3 では、新しいマジック・メソッドである __callStatic() が追加されています。このメソッドは __call() マジック・メソッドと同じように動作します (__call() マジック・メソッドはクラスの中で定義されていないメソッドやクラスの中では見えないメソッドに対する呼び出しを処理するために設計されています)。しかし __callStatic() は静的なメソッドの呼び出しを処理するために設計されているため、__callStatic() を利用するとメソッドのオーバーロードを適切に設計することができます。このメソッドの使い方の例は次の通りです。
リスト 1.
__callStatic() と __call() の使い方の例
class Foo
{
public static function __callStatic(
$name,
$args
)
{
echo "Called method $name statically";
}
public function __call(
$name,
$args
)
{
echo "Called method $name";
}
}
Foo::dog(); // outputs "Called method dog statically"
$foo = new Foo;
$foo->dog(); // outputs "Called method dog"
|
1 つの注意点として、PHP では __callStatic() メソッドの定義が必ず必要です。つまり __callStatic() メソッドは public でなければならず、また静的メソッドとして宣言しなければなりません。同様に、__call() マジック・メソッドも他のすべてのマジック・メソッドと同様、public として定義しなければなりません。
PHP の便利な機能の 1 つとして、可変変数があります。可変変数とは、変数のストリング値を使って別の変数の名前を指定できるというものです。つまり次のようなことができます。
リスト 2. 可変変数
$x = 'y';
$$x = 'z';
echo $x; // outputs 'y'
echo $y; // outputs 'z'
echo $$x; // outputs 'z'
|
以下のように、同じ概念を関数にも、さらにはクラス・メソッドにも使うことができます。
リスト 3. 可変関数とクラス・メソッド名
class Dog
{
public function bark()
{
echo "Woof!";
}
}
$class = 'Dog'
$action = 'bark';
$x = new $class(); // instantiates the class 'Dog'
$x->$action(); // outputs "Woof!"
|
PHP V5.3 では新たな機能として、静的呼び出しを行うためにクラスを指定する際、クラスの名前を変数にすることができます。これによって、いくつかの新しい可能性が生まれます。この例を以下に示します。
リスト 4. クラスの名前を可変にする
class Dog
{
public static function bark()
{
echo "Woof!";
}
}
$class = 'Dog';
$action = 'bark';
$class::$action(); //outputs "Woof!"
|
この追加によって PHP の可変変数機能が完全になり、PHP でのほとんどすべての状況で可変変数を使えるようになります。
静的なメソッドとメンバーの使い方に関する、もう 1 つの便利な機能強化である、遅延静的バインディングを見てみましょう。
V5.3 以前の PHP で面倒だったことの 1 つが静的なメソッドとメンバーの扱い方です。現在まで、静的参照 (例えば自分自身または __CLASS__ による静的参照) は、関数が定義されたクラスのスコープで解決されています。問題は、クラスが継承されて新しい子クラスから呼び出しが行われる場合には参照が正しくなくなってしまうことです。PHP V5.3 には遅延静的バインディングが追加され、この問題が緩和されています。わかりやすく説明するために、以下のような静的メソッドを持つクラスを作成しましょう。
リスト 5. 静的メソッド
test() を持つクラス Foo
class Foo
{
protected static $name = 'Foo';
public static function test()
{
return self::$name;
}
}
|
このクラスを継承してみましょう。この子クラスで $name メンバーを再定義します。
リスト 6. 親クラス
Foo を継承する子クラス Bar
class Bar extends Foo
{
protected static $name = 'Bar';
}
|
リスト 7 で静的な呼び出しを行います。
リスト 7.
test() メソッドを静的に呼び出すecho Bar::test(); |
この呼び出しによって Foo というストリングが出力されます。なぜなら、test() メソッドの中で行われている self::$name 参照は Foo クラスによって行われるからです。このようなバインディングが行われるのは、この関数が Foo クラスで定義されているためです。
PHP V5.3 では static というキーワードが追加され、現在のクラスに対する参照を行えるようになっています。そこで上記の Foo クラスを変更して static キーワードを使用すると (リスト 8)、今度は Bar が出力されることがわかります。
リスト 8. static キーワードを使用する
class Foo
{
protected static $name = 'Foo';
public static function test()
{
return static::$name;
}
}
class Bar
{
protected static $name = 'Bar';
}
echo Bar::test(); // outputs 'Bar'
|
このように、static キーワードに関して注意しなければならないことは、static キーワードを指定することで動作が変わるということです。つまり、静的呼び出しには通常の継承ルールが当てはまらないのです。static キーワードは、関数が定義されたクラスの中ではなく、現在のクラスの中で単純に呼び出しを解決しようとします。これは重要な注意点です。
ここまで、静的なメソッドとメンバーに関する機能強化をいくつか見てきたので、今度は PHP V5 の非常に便利な部分である Standard PHP Library に追加された新しいクラスをいくつか見てみましょう。
SPL (Standard PHP Library) は、標準的な問題を解決するために PHP V5 に追加されたインターフェースやクラスを集めたものです。そうした問題としては、オブジェクトを繰り返し処理可能にすることや、オブジェクトを配列のように動作させること、そしてリンク・リストを実装することなどがあります。これらのクラスやメソッドを使用するメリットは、これらのクラスやメソッドが最初から PHP に用意されているので、PHP を使って実装した場合よりも処理が速いことです。また多くの場合、これらのクラスやメソッドを使うことによって PHP の内部関数の多くがこれらのオブジェクトを直接使えるようになります (例えば Iterator インターフェースを利用すると、foreach 構成体を使ってオブジェクトに対する繰り返しの処理を行うことができます)。
PHP V5.3 では、さらにいくつかのクラスが SPL に追加されています。先ほど参照したクラスは SPL の SplDoublyLinkedList クラスのダブル・リンク・リストを実装したものです。このクラスは SPL に追加された他の 2 つの新しいクラス (スタックを実装する SplStack と、キューを実装する SplQueue) で使われています。
では SplStack クラスを使ってスタックを実装する方法を見てみましょう。
リスト 9.
SplStack クラスを使う
$stack = new SplStack();
// push a few new items on the stack
$stack->push('a');
$stack->push('b');
$stack->push('c');
// see how many items are on the stack
echo count($stack); // returns 3
// iterate over the items in the stack
foreach ( $stack as $item )
echo "[$item],";
// the above outputs: [c],[b],[a]
// pop an item off the stack
echo $stack->pop(); // returns 'c'
// now see how many items are on the stack
echo count($stack); // returns 2
|
SqlQueue の動作も SplStack の動作と似ていますが、SqlQueue はキューらしく動作します (つまりFIFO (First In First Out) であり、スタックのように LIFO (Last In Last Out) ではありません)。またヒープの実装があり (SplHeap)、ある種の状況のための特定のキューの実装とヒープの実装もあります (SplMinHeap、SplMaxHeap、SplPriorityQueue)。
もう 1 つ、追加された便利なクラスが SplFixedArray クラスです。このクラスは名前からわかるように、固定サイズの配列の実装です。しかしこのクラスの処理はかなり高速であり、実際にベンチマークでは PHP に組み込まれた配列の実装よりも 10 パーセントから 30 パーセント高速なことが実証されています。このように高速な理由は、サイズが固定された配列であり、PHP でのデフォルトの配列のようにサイズが可変ではないこと、また数字以外のインデックスが許可されていないことによるものです。リスト 10 はこのクラスの使い方を示しています。
リスト 10.
SplFixedArray
$array = new SplFixedArray(3);
$array[0] = 'dog';
$array[1] = 'cat';
$array[2] = 'bird';
$a->setSize(4); // increase the size on the fly
$array[3] = 'mouse';
foreach ( $array as $value )
echo "[$value],";
Output:
[dog],[cat],[bird],[mouse]
|
また、新しいイテレーター・クラスが追加されています (FilesystemIterator と GlobIterator)。これらのクラスは PHP の他のイテレーター・クラスと同じように動作しますが、特定の状況専用に設計されています。
SPL でのもう 1 つの変更点は、PHP V5.3 では常に SPL が有効である点です。これまでのバージョンの PHP V5 ではコンパイル時に SPL を無効にすることができましたが、PHP V5.3 ではそれができなくなりました。
新たなものが SPL に追加されたことにより、便利で使いやすい機能がいくつか PHP に追加され、またデータ構造の実装も追加されています (ダブル・リンク・リストやスタック、ヒープ、キューなど)。これらのクラスを使うことでユーザーによる既存の実装を置き換えることができ、それによって高速化と、PHP のさまざまな関数や構成体との適切な統合を実現することができます。
ここまでで、SPL に新たに追加されたものをいくつか調べたので、今度は PHP V5.3 での OOP に関する重要な改善事項として循環型ガーベッジ・コレクションが追加され、パフォーマンスとメモリーの使用が大きく改善されていることを説明しましょう。
パフォーマンスの観点で PHP 開発者が遭遇する問題の 1 つにガーベッジ・コレクションがあります。PHP のガーベッジ・コレクターは非常に単純であり、基本的な動作としてはオブジェクトがスコープ内になくなると、そのオブジェクトに対してガーベッジ・コレクションが行われます。このガーベッジ・コレクターは内部で参照カウンターを使ってガーベッジ・コレクションを行います。そのため参照カウンターがゼロになると (つまりオブジェクトに対する参照がなくなると)、そのオブジェクトはガーベッジ・コレクションによってメモリーから削除されます。
このガーベッジ・コレクションは非常にうまく動作しますが、あるオブジェクトが親子関係にある別のオブジェクトを参照している状況では問題になる可能性があります。この状況では、これらのオブジェクトに対する参照カウンターはガーベッジ・コレクションによる処理が行われないため、これらのオブジェクトが使用していたメモリーは参照されないままメモリー内に残り、そのリクエストの終了まで割り当てが解除されません。この問題が起こる場合の例を見てみましょう。
リスト 11. PHP V5.2 とそれ以前でガーベッジ・コレクションが適切に行われない、親子関係のあるクラス
class Parent
{
public function __construct()
{
$this->child = new Child($this);
}
}
class Child
{
public function __construct(
Parent $parent
)
{
$this->parent = $parent;
}
}
|
この場合、Parent クラスのインスタンスを作成した後にそのインスタンスがスコープ外になると、その都度そのメモリーが解放されずに残るため、このスクリプトによるメモリー使用量が増え続けます。この問題をユーザー側で解決する方法がいくつかあり、例えば親クラスに対するデストラクターを作成して子オブジェクトを直接解放する方法などがあります。この方法では必ずこのデストラクターを呼び出してから親クラスによる参照を解除する必要があります。この方法は有効ですが、コードが非常に複雑になります。
PHP V5.3 では、ガーベッジ・コレクターがこれらの循環参照を検出し、循環参照に使用されているメモリーを解放することができます。そのため PHP が使用するメモリー量はこのスクリプトを実行する間、一定に保たれます。Parent クラスに対する参照が削除されるたびに、その Parent クラスの中にある Child クラスへの参照もガーベッジ・コレクションによって処理されます。
PHP はオブジェクト指向プログラミングのサポートに関して、PHP V4 当時の貧弱なサポートから、PHP V5 での大きく改善された追加機能や、その後のバージョンでの細かな調整により、大きな進歩を遂げています。そして PHP V5.3 では非常に興味深い改善がいくつか行われており、その中には新しい __callStatic() マジック・メソッドのような構文強化や、動的な静的呼び出し、遅延静的バインディング、静的メソッド、そしてメンバーのサポートなどが含まれています。SPL にダブル・リンク・リストやスタック、ヒープ、キューなどの実装が新たに追加されたことにより、いくつかの一般的なデータ構造をすぐに利用できるようになり、しかもそれらを容易に使用することができます。最後に、長年待ち望まれていた循環型ガーベッジ・コレクターによって自己参照クラスに関するメモリーやパフォーマンスの問題が解決されています。実装されているガーベッジ・コレクターは大幅に改善されており、循環型のインスタンス用のメモリーを適切に解放することができます。こうしたさまざまな機能によって、PHP V5.3 はオブジェクト指向プログラミングのための、はるかに強力な言語になっています。
学ぶために
- Zend Developer Zone にはメモリー管理のための関数のドキュメントが用意されています。
- 「PHP V5 マイグレーション・ガイド」を読み、PHP V4 で開発されたコードを V5 にマイグレートする方法を学んでください。
- 「Connecting PHP Applications to Apache Derby」には Windows® に PHP をインストールして構成するための方法が解説されています (一部のステップは Linux® にも当てはまります)。
- PHP.net には PHP 開発者のためのリソースが集まっています。
- 「Recommended PHP reading list」を調べてみてください。
- developerWorks には他にも PHP に関する資料が豊富に用意されています。
- IBM developerWorks の PHP project resources を利用して PHP のスキルを磨いてください。
- developerWorks podcasts では、ソフトウェア開発者のための興味深いインタビューや議論を聞くことができます。
- PHP でデータベースを使うのであれば、Zend Core for IBM を調べてみてください。これはシームレスでそのまま使用でき、インストールも容易な、IBM DB2 V9 をサポートする PHP の開発環境であり実動環境です。
- developerWorks の Technical events and webcasts で最新情報を入手してください。
- IBM オープンソース開発者にとって関心のある、世界中で今後開催される会議や業界展示会、ウェブキャスト、その他のイベントについて調べてみてください。
- developerWorks の Open source ゾーンをご覧ください。オープンソース技術を使った開発や、IBM 製品でオープンソース技術を使用するためのハウ・ツー情報やツール、プロジェクトの更新情報など、豊富な情報が用意されています。
- IBM とオープンソース技術、そして製品機能を調べ、学ぶために、無料の developerWorks On demand demos をご覧ください。
製品や技術を入手するために
- 皆さんの次期オープンソース開発プロジェクトを IBM ソフトウェアの試用版を使って革新してください。ダウンロード、あるいは DVD で入手することができます。
- IBM 製品の評価版をダウンロードし、DB2® や Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品をお試しください。
議論するために
- developerWorks blogs から developerWorks のコミュニティーに加わってください。
- developerWorks の PHP Forum: Developing PHP applications with IBM Information Management products (DB2, IDS) に加わってください。