Iteratorインターフェイスを使うメリット
これまで、Iteratorインターフェイスとはどのようなものか、どのように利用するのかについて簡単に説明した。ここでイテレーション処理をIteratorクラスとして実装することのメリットを考えておきたい。
前項でも触れたが、コレクションへ単純にアクセスしていく方法でイテレーション処理を実装すると、データを加工する処理をループ内に記述することになり、データ構造やオブジェクトの構造に依存した処理が埋め込まれる。このため、データの利用個所が増えれば増えるほど、データ構造やその処理方法が変化した場合に煩雑な問題を抱えてしまう。
これを回避するために用いられるのが、データの取得・加工に関する処理をすべてオブジェクト内に隠蔽(いんぺい)してしまい、外部へはイテレーションに必要な繰り返し処理のためのAPIを提供する方法だ。
SPLのIteratorインターフェイスは、外部への統一APIとしてのメソッドを定義したもので、この方法を容易に実現できる。また、先の例のとおり、Iteratorインターフェイスとforeachを組み合わせて用いることで明示的なメソッド呼び出しも不要となるため、呼び出し側をより簡潔な形で実装できる。
このように、Iteratorインターフェイスを用いることでデータ構造とメインロジックを切り離すことが容易になり、コードの再利用性を高めることができるのだ。
IteratorAggregateインターフェイス
イテレータを実装するうえで欠かせないもう一つの存在として、IteratorAggregateインターフェイスがある。
これまで説明してきたIteratorインターフェイスは、実装したクラスそれ自体がイテレータとしての機能を持つものだ。これをそのまま拡張すると、あるデータ構造に依存する処理をまとめて記述することになる。
しかし、実際には1種類のデータに対し1つの処理方法しかないとは限らず、むしろさまざまな処理のパターンを用意する方が一般的だ。データの処理にさまざまなパターンがある場合には、オブジェクトをデータ格納部とデータ処理部に分割し、データを格納するオブジェクトに対して集約的な関係になるよう実装すると非常に都合が良い。
そのような関係を実装するために用意されているのが、IteratorAggregateインターフェイスだ。IteratorAggregateインターフェイスは、実装されたオブジェクト自体にはイテレータとしての機能を持たず、オブジェクト内部で別のIteratorオブジェクトを呼び出すことでイテレータとしての機能を実現する。
以下に、IteratorAggregateインターフェイスを実装した例を示す。このクラスは、Iteratorの項で紹介したSquareクラスを呼び出すことでイテレータとして振る舞う。
<?php |
list2 |
0:10000 |
結果 |
結果を見ると分かるように、SquareAggregateクラス自体にはイテレータの機能を実装していないにもかかわらず、foreachのループに入った際にSquareクラスと同様のイテレーションが実行されている。
これは、foreach内でIteratorAggregateインターフェイスのgetIteratorメソッドが自動的に呼び出され、その結果生成されたSquareクラスのインスタンスがイテレーションに利用されたためである。
このように、IteratorAggregateインターフェイスを使うと外部のクラスを利用してイテレータとしての機能を持つことが可能になり、さらにforeachを利用することで呼び出し側での明示的な記述なしにイテレーションを実現できる。
また、上述のgetIteratorメソッドで呼び出すクラスを動的に変更できる仕組みを実装すれば、さまざまなイテレータを利用できるようになり、処理方法のみを簡単に切り替えられる。
ArrayObject/ArrayIteratorクラス
IteratorとIteratorAggregateの2つのインターフェイスを紹介したが、SPLではこれらのインターフェイスを継承したクラスが最初から数多く実装されている。ここでは、その好例といえるArrayObjectとArrayIteratorを紹介しよう。
ArrayObjectとArrayIteratorは、SPLの各クラス群の中でも象徴的なものだといっていい。それぞれ、IteratorインターフェイスとIteratorAggregateインターフェイスを中心に、配列の動作に必要な各クラス、インターフェイスを継承したもので、Iteratorデザインパターンの実装となっている。
ArrayObjectは、PHPのオブジェクトを本来PHPではプリミティブである配列と同様に扱えるようにしたものだ。オブジェクトであることに変わりはないため完全なエミュレーションにはなっていないが、基本的な挙動は配列とほとんど変わらない。
ArrayIteratorはArrayObjectの外部イテレータで、それ自体もArrayObjectと同様に配列オブジェクトとして振る舞う。
注:ArrayObjectはArrayAccess、Countable、IteratorAggregateの各インターフェイスの実装で、ArrayIteratorはArrayAccess、Countable、SeekableIteratorの実装である。ArrayAccess、Countable、SeekableIteratorはすべてSPLで提供されるインターフェイスなので、個別に興味がある場合はSPL - Standard PHP Libraryを見てほしい。 |
この2つは、多くの場合に対で使われる。最も単純に利用した場合の例を示そう。
<?php |
list3 |
0:10 |
結果 |
確かに$arrayの各要素が$objのプロパティとなり、順次アクセスしている様子が見て取れる。だが、さすがにこれだけではあまり差が分からないし、ArrayObjectにするだけ無駄に見えてしまうだろう。
そこで、この配列から奇数番目の要素のみを抽出するようなロジックを、ArrayIteratorを拡張して実装してみよう。
<?php |
list4 |
0:10 |
結果 |
奇数番目(キーは0スタートである点に注意)の配列要素のみを取得できた。従来、このような実装はforeachの中に行われるのが一般的だったが、ArrayIteratorを使うことでイテレーションの処理内容をオブジェクト側に記述できるようになった。
上の例のようにArrayObjectの第3引数としてイテレータのオブジェクト名を渡してやることで、利用するイテレータを切り替えられる。配列のさまざまなイテレーション実装の際に適切に、これらのオブジェクトを用いればコードの見通しも良くなり、メンテナンス性も担保できるだろう。
今回は、SPLの代表的なインターフェイスやクラスを取り上げた。SPLにはまだまだ多くのクラスが用意されているので、ぜひともマニュアルなどを参照しながら理解を深め、活用してほしい。
2/2 |
Index | |
「SPL」でイテレーションを使いこなす | |
Page1 標準PHPライブラリ「SPL」 Iteratorインターフェイス |
|
Page2 Iteratorインターフェイスを使うメリット IteratorAggregateインターフェイス ArrayObject/ArrayIteratorクラス |
PHP5で広がる! 開発環境 |
PHP関連記事 |
例外処理の実装を把握する PHP5で広がる! 開発環境(1) PHP4のサポートが終了し、いよいよPHP5への移行を視野に入れる時期が来た。PHP5の機能を生かした開発のポイントを紹介 |
|
クライアントPCに言語環境を入れる理由 Mac OS X+PHPでオールインワン環境(準備編) Webアプリ開発者に人気のMac OS X。効率的な開発のために複数バージョンのPHPを実行する環境を構築してみよう |
|
PHPに押し寄せるリスクと国際化の波 PHPカンファレンス2008レポート(前編) PHP4のサポートが完全に終了する。多くの新機能が投入されるPHP5.3へ移行か、国際化対応で開発が遅れるPHP6を待つか |
|
PHPによる大規模商用サービスの裏側 PHPカンファレンス2008レポート(中編) 企業のWebアプリケーション開発現場で利用されるPHP。開発現場の裏側にはさまざまなドラマが隠されている |
|
PHPユーザーは本当にほかの言語を知らないのか? PHPカンファレンス2008レポート(後編) PHPは本当にダメな言語なのだろうか。Perl、Ruby、Python、Java、JavaScriptの使い手が白熱した議論を行った |
|
- プログラムの実行はどのようにして行われるのか、Linuxカーネルのコードから探る (2017/7/20)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。最終回は、Linuxカーネルの中では、プログラムの起動時にはどのような処理が行われているのかを探る - エンジニアならC言語プログラムの終わりに呼び出されるexit()の中身分かってますよね? (2017/7/13)
C言語の「Hello World!」プログラムで使われる、「printf()」「main()」関数の中身を、デバッガによる解析と逆アセンブル、ソースコード読解などのさまざまな側面から探る連載。今回は、プログラムの終わりに呼び出されるexit()の中身を探る - VBAにおけるFileDialog操作の基本&ドライブの空き容量、ファイルのサイズやタイムスタンプの取得方法 (2017/7/10)
指定したドライブの空き容量、ファイルのタイムスタンプや属性を取得する方法、FileDialog/エクスプローラー操作の基本を紹介します - さらば残業! 面倒くさいエクセル業務を楽にする「Excel VBA」とは (2017/7/6)
日頃発生する“面倒くさい業務”。簡単なプログラミングで効率化できる可能性がある。本稿では、業務で使うことが多い「Microsoft Excel」で使えるVBAを紹介する。※ショートカットキー、アクセスキーの解説あり
|
|