0.イントロ。
標準のphpパッケージには2つの興味深いインターフェイスがあり、言語のオブジェクトの動作を大幅に変更できます。
これらはIteratorとArrayAccessです。 1つ目では、each、foreach、forなどの構造を介してオブジェクトを反復処理できます。 次に、2番目の方法では、使い慣れた$ array [] = 'newItem'を使用して、オブジェクトを配列としてアクセスできます。 したがって、配列を完全にエミュレーションするには、オブジェクトに両方のインターフェイスを実装する必要があります。
1.イテレータ。
イテレータ(別名カーソル)は、動作デザインパターンです。 phpでは、Iteratorインターフェイスで表され、次のメソッドの実装が必要です。
- public function rewind()-ポインターをゼロ位置にリセットします。
- public function current()-現在の値を返します。
- public function key()-現在の要素のキーを返します;
- public function next()-次の要素にシフトします。
- public function valid()-Iterator :: rewind()またはIterator :: next()の後に呼び出して、現在の位置が有効かどうかを確認する必要があります。
したがって、これらのメソッドは、通常のリセット()、現在()、キー()、次()に類似しています。
例1:
class Iteratable implements Iterator { protected $_position = 0; protected $_container = array ( 'item1', 'item2', 'item3' ); public function __construct() { $this->_position = 0; } public function rewind() { $this->_position = 0; } public function current() { return $this->_container[$this->_position]; } public function key() { return $this->_position; } public function next() { ++$this->_position; } public function valid() { return isset($this->_container[$this->_position]); } } $iteratable = new Iteratable; foreach ($iteratable as $item) { var_dump($iteratable->key(), $item); }
しかし、現在のクラスはまだ擬似配列ではありません。 今では、含まれている値を変更する機会はまだありません。
2. ArrayAccess。
このインターフェイスの実装により、利用可能な関数の配列としてオブジェクトにアクセスできます。 インターフェースには4つの抽象メソッドが含まれます。
- abstract public boolean offsetExists(mixed $ offset)-指定されたキーの値が存在するかどうか。
- abstract public mixed offsetGet(mixed $ offset)-インデックスによって値を取得します。
- abstract public void offsetSet(混合$オフセット、混合$値)-インデックスで値を設定します。
- abstract public void offsetUnset(mixed $ offset)-値を削除します。
例2:
class ArrayAccessable implements ArrayAccess { protected $_container = array(); public function __construct($array = null) { if (!is_null($array)) { $this->_container = $array; } } public function offsetExists($offset) { return isset($this->_container[$offset]); } public function offsetGet($offset) { return $this->offsetExists($offset) ? $this->_container[$offset] : null; } public function offsetSet($offset, $value) { if (is_null($offset)) { $this->_container[] = $value; } else { $this->_container[$offset] = $value; } } public function offsetUnset($offset) { unset($this->_container[$offset]); } } $array = new ArrayAccessable(array('a', 'b', 'c', 'd', 'e' => 'assoc')); var_dump($array); unset($array['e']); var_dump('unset: ', $array); $array['meta'] = 'additional element'; var_dump('set: ', $array); var_dump(count($array));
これで、ArrayAccessableクラスのインスタンスは配列のように機能します。 しかし、count()はまだ1を返します(なぜですか? http://www.php.net/manual/en/function.count.phpを参照 )。
3.カウント可能。
インターフェイスには、count()で使用するために作成されたメソッドが1つだけ含まれています。
- abstract public int count(void)-オブジェクトの要素の数。
例3
class CountableObject implements Countable { protected $_container = array('a', 'b', 'c', 'd'); public function count() { return count($this->_container); } } $countable = new CountableObject; var_dump(count($countable));
しかし、私たちのオブジェクトはまだ配列ではなくオブジェクトとしてシリアライズされています...
4.シリアライズ可能。
オブジェクトのシリアル化方法を再定義できるインターフェイス。
名前を話す2つのメソッドが含まれています。
- 抽象パブリック文字列のシリアル化(void);
- 抽象パブリック混合非直列化(文字列$直列化)。
例4
class SerializableObject implements Serializable { protected $_container = array('a', 'b', 'c', 'd'); public function serialize() { return serialize($this->_container); } public function unserialize($data) { $this->_container = unserialize($data); } } $serializable = new SerializableObject; var_dump($serializable); // SerializableObject file_put_contents('serialized.txt', serialize($serializable)); $unserialized = unserialize(file_get_contents('serialized.txt')); var_dump($unserialized); // SerializableObject
これで、オブジェクトはそれ自体ではなく、データのみをシリアル化します。
5.結果。
上記のクラスを1つに組み合わせることで、配列のように動作するオブジェクトを取得します。
唯一の欠点は、array_pop()などの関数が機能しないことです。
解決策として、php 5.3 __invoke()の新しいマジックメソッドを使用できます。これにより、オブジェクトを関数として呼び出して、これらの関数を機能させることができます。
public function __invoke(array $data = null) { if (is_null($data)) { return $this->_container; } else { $this->_container = $data; } } $array = new SemiArray(array('a', 'b', 'c', 'd', 'e' => 'assoc')); $tmp = $array(); array_pop($tmp); $array($tmp); var_dump('array_pop', $array);
オプションはバックアップで、他のオプションはコメントで待っています。
結果のクラスの完全なリスト:
class SemiArray implements ArrayAccess, Countable, Iterator, Serializable { protected $_container = array(); protected $_position = 0; public function __construct(array $array = null) { if (!is_null($array)) { $this->_container = $array; } } public function offsetExists($offset) { return isset($this->_container[$offset]); } public function offsetGet($offset) { return $this->offsetExists($offset) ? $this->_container[$offset] : null; } public function offsetSet($offset, $value) { if (is_null($offset)) { $this->_container[] = $value; } else { $this->_container[$offset] = $value; } } public function offsetUnset($offset) { unset($this->_container[$offset]); } public function rewind() { $this->_position = 0; } public function current() { return $this->_container[$this->_position]; } public function key() { return $this->_position; } public function next() { ++$this->_position; } public function valid() { return isset($this->_container[$this->_position]); } public function count() { return count($this->_container); } public function serialize() { return serialize($this->_container); } public function unserialize($data) { $this->_container = unserialize($data); } public function __invoke(array $data = null) { if (is_null($data)) { return $this->_container; } else { $this->_container = $data; } } }
テスト:
$array = new SemiArray(array('a', 'b', 'c', 'd', 'e' => 'assoc')); var_dump($array); $array->next(); var_dump('advanced key: ', $array->key()); unset($array['e']); var_dump('unset: ', $array); $array['meta'] = 'additional element'; var_dump('set: ', $array); echo 'count: '; var_dump(count($array)); file_put_contents('serialized.txt', serialize($array)); echo 'unserialized:'; var_dump($array); // SemiArray $array = unserialize(file_get_contents('serialized.txt')); $tmp = $array(); array_pop($tmp); $array($tmp); var_dump('array_pop', $array);
6.範囲。
6.1。 たとえば、データベースからの選択の結果。
警告! 擬似コード
class Rowset extends SemiArray { protected $_total; public function __construct() { $this->_total = $db->query('SELECT FOUND_ROWS() as total')->total; } public function getTotal() { return $this->_total; } } $rowset = new Rowset(); while ($obj = mysql_fetch_object($res)) { $rowset[] = $obj; } foreach ($rowset as $row) { // ... } $rowset->getTotal(); // total row count
7.アウトロ。
この記事は教育目的のために書かれており、PHPの組み込みクラスArrayObject( http://www.php.net/manual/en/class.arrayobject.php )の実装は既に利用可能です。