はじめに
今回はPHPでコレクションクラスを自作する方法を紹介します。
作成するコレクションクラスは、コレクションクラス内に保持する配列の要素の型を指定しない、汎用的なクラスです。
コレクションクラスを自作できると、更にファーストクラスコレクションの作り方がわかるようになります。
ファーストクラスコレクションについては、『ThoughtWorksアンソロジー』を読んで知りました。
『ThoughtWorksアンソロジー』には「オブジェクト指向エクササイズ」という、オブジェクト指向を身につけるための練習方法が載っているのですが、どうやったらオブジェクト指向を実践できるのか、イメージがわからない方にとって参考になる内容だと思います。
コレクションクラスとは
まずはPHPにおけるコレクションクラスについて、自分の認識を書くことにします。
コレクションクラスとは、「配列をラップしたクラスのこと」と考えています。
そのためコレクションクラスはインスタンス変数として、配列を持ちます。
ファーストクラスコレクションとは
次にファーストクラスコレクションについては「コレクションクラスが保持する配列の要素が特定のクラスであること」と考えています。
例えば “UserCollection” というファーストクラスコレクションは、インスタンス変数として配列を持っていますが、その配列に格納されている要素はすべて “User” クラスである、といった具合です。
それではファーストクラスコレクション(コレクションクラス)はどういったことをするクラスなのかを検討します。
『ThoughtWorksアンソロジー』の「5章 オブジェクト指向エクササイズ」では、”ファーストクラスコレクションを使用すること”がルールの1つに挙げられています。
そして、そのルールについて次のように説明しています。
コレクションクラスを持つクラスには、他のメンバ変数を持たせないようにしてください。各コレクションはそれぞれ独自のクラスにラップすることで、コレクションに関する振る舞いをそのクラスに置くことができるようになります。
『ThoughtWorksアンソロジー』
配列やコレクションを扱うコードは複雑になりがちです。
ファーストクラスコレクションは特定のクラスを扱う専用のコレクションクラスなので、そのクラスに関するロジックをコレクションクラス内に閉じ込めることができます。
そうすることで、管理・変更しやすいコードを書くことができるようになります。
コレクションに関する振る舞いをクラスに定義するとは
コレクション(PHPの場合は配列)に関する振る舞いをクラスに定義するというのは、例えば「コレクションのサイズを取得すること」や「コレクションの各要素に対して処理を実行する」メソッドを作ることです。
この後で作成する Collection
クラスを使ったコード例を下記に示します。
今回作成するコレクションクラスの使い方サンプル
・コレクションのサイズを取得するサンプル
<?php
$collection = new \App\Collection(['red', 'yellow', 'blue']);
$collection->count();
// => 3
コレクションクラスを自作する
“Collection”クラスの実装は下記になります。
コレクションクラスは”ArrayAccess”と”IteratorAggregate”をimplementします。
2つともPHPに組み込まれているインタフェースなので、どういうメソッドが定義されているかは、PHPのドキュメントを参照ください。
<?php
namespace App;
use ArrayAccess;
use ArrayIterator;
use IteratorAggregate;
class Collection implements ArrayAccess, IteratorAggregate
{
/**
* @var array
*/
protected $items = [];
public function __construct($items = [])
{
if (is_array($items)) {
$this->items = $items;
}
if ($items instanceof self) {
$this->items = $items->all();
}
$this->items = (array)$items;
}
public function all()
{
return $this->items;
}
public function count()
{
return count($this->items);
}
public function offsetExists($offset)
{
return array_key_exists($offset, $this->items);
}
public function offsetGet($offset)
{
return $this->items[$offset];
}
public function offsetSet($offset, $value)
{
if (is_null($offset)) {
$this->items[] = $value;
} else {
$this->items[$offset] = $value;
}
}
public function offsetUnset($offset)
{
unset($this->items[$offset]);
}
public function getIterator()
{
return new ArrayIterator($this->items);
}
}
まとめ
今回はコレクションクラスの作成方法について紹介しました。
上記の”Collection”クラスは配列の要素のクラスについては指定していない、汎用的なコレクションクラスとなっています。
ファーストクラスコレクションを作る場合は、”配列の要素が特定のクラス”であることを保証する仕組みが必要になると思います。
サンプルに使用した”count()”メソッドだけでなく、「要素を追加するメソッド」や「要素を削除するメソッド」など用途に応じて拡張する必要があるでしょう。
データと振る舞いをクラス内に閉じ込めることで、管理しやすいコードを実現できるのがコレクションクラス(ファーストクラスコレクション)の利点です。