SPLでイテレータを使ってみる
PHPにはSPL(Standard PHP Library)という便利……というほどには充実してないライブラリがあるんだけど、いまいち知名度が低いようで、あまり使ってるのを見たことがない。標準で組み込まれてるのに。
ちなみにC言語からプログラムを覚えた身としては、どうしてもC++のSTL(Standard Template Library)を連想してしまうのだが、STLとは毛色が違う。全然関係ない。
SPLが提供するもの
SPLの機能をおおざっぱに分けると次の3種類になる(細かくは8種類)。
- イテレータ
- オブザーバ
- 例外
基本的にどれもJavaを意識した感じ。
イテレータは実装することでオブジェクトをforeachとかで回したりフィルタリングできるようになるというもの。
オブザーバはデザインパターンのオブザーバパターンを実装するためのもの。
例外は標準Exceptionクラスから派生したInvalidArgumentExceptionとかOutOfBoundsExceptionとかそういうやつ。
その他に〜ableなインターフェイスがいくつか(count()で要素数を求められるようにするCountableとか)。
括弧付きで書いた8種類はだいたいこれらのものから派生したやつで、SimpleXMLIteratorとか、DirectoryIteratorとかそんな感じ。
イテレータを使ってみる
PHPはとりあえず何でも配列に突っ込んでforeach ($array as $key => value)
で簡単に処理できちゃうので、わざわざイテレータとか考えなくてもいいのかもしれないけど、先日、データのコレクション+ちょっとした付加情報を持ったクラスを作ってる時にふとSPLの存在を思い出したので実装してみた。
こいつは基本的にデータの配列なんだけど、この配列の名前と処理方法も一緒に持たせたかったので次のようなクラスを作った(簡略化してます)。
まずは普通の実装。
<?php class FooList { private $name; private $type; private $list; // getter/setterの定義 } ?>
でこんな風に使おうかと思ってた。
<?php $type = $fooList->getType(); $list = $fooList->getList(); foreach ($list as $key => $value) { switch ($type) { ... } } ?>
そしてイテレータ版。イテレータとかいいつつ自分では実装してない罠w
<?php class FooList extends ArrayObject { private $name; private $type; // $nameと$typeのgetter/setter } ?>
<?php $type = $fooList->getType(); foreach ($fooList as $key => $value) { switch ($type) { ... } } ?>
こんな風にオブジェクトがforeachで回せるようになる。$keyと$valueに何が入ってくるかは実装次第。
だがしかし上記は自分ではイテレータを実装していないという驚愕の事実!!
ちまちまとimplements IteratorしてたらArrayObjectという最初からてんこ盛りで実装済みのクラスを発見してしまったので派生させることにしたw
自分で実装する場合はcurrent()やnext()といったメソッドを実装する必要があるが、ArrayObjectは配列をベースに設計されたクラスなのでその辺は既に実装されている。
そしてこいつはイテレータ以外にもArrayAccessとかCountableとかも実装されてて、まるで配列であるかのようにアクセスできるようになっている。なので、オブジェクトのくせにcount($fooList)
とか$fooList[2]
とかもできちゃう。
こういった実装は便利な反面「countって何の数が返ってくるんだよ」とか「key/valuは何が入ってくるんだよ」という混乱を招くのでよく考えて利用した方がいいかもしれない。
今回の場合は配列が主体なのでいいかな、と思う。つまり(PHPではないけど)配列にlengthプロパティしかなかったところへ、nameプロパティとtypeプロパティを追加してやったという感じ。
ちなみに昔やった案件ではディレクトリ内のファイルを順次処理するのにDirectoryIteratorとFilterIteratorを組み合わせて、「処理対象のファイルだけ」ぐるぐる回すクラスなどを作ったりした。
さぁ、キミも今すぐSPLを使おう!
requireとかしなくても標準で組み込まれてるよ!
え、PHP自体使わないって?