配列っぽいクラスを書いてみる

http://d.hatena.ne.jp/hope-echoes/20080424/1209031875 の続き。
PHP: ArrayObject - Manual を参考に実装してみる。



<?php

class Ary implements ArrayAccess, Countable, IteratorAggregate
{
    public function __construct($values = array())
    {
        $this->values = $values;
    }

    // {{{ ArrayAccess

    public function offsetExists($offset)
    {
        return isset($this->values[$offset]);
    }

    public function offsetGet($offset)
    {
        if (!array_key_exists($offset, $this->values)) {
            throw new OutOfBoundsException;
        }
        return $this->values[$offset];
    }

    public function offsetSet($offset, $value)
    {
        if (is_null($offset)) {
            $this->values[] = $value;
        } else {
            $this->values[$offset] = $value;
        }
    }

    public function offsetUnset($offset)
    {
        if (array_key_exists($offset, $this->values)) {
            unset($this->values[$offset]);
        }
    }

    // - ArrayAccess }}}
    // {{{ Countable

    public function count()
    {
        return count($this->values);
    }

    // - Countable }}}
    // {{{ IteratorAggregate

    public function getIterator()
    {
        return new AryIterator($this->values);
    }

    // - IteratorAggregate }}}

    protected $values;
}



class AryIterator implements ArrayAccess, Countable, SeekableIterator
{
    public function __construct($values = array())
    {
        $this->values = $values;
        $this->rewind();
    }

    // {{{ ArrayAccess

    public function offsetExists($offset)
    {
        return isset($this->values[$offset]);
    }

    public function offsetGet($offset)
    {
        if (!array_key_exists($offset, $this->values)) {
            throw new OutOfBoundsException;
        }
        return $this->values[$offset];
    }

    public function offsetSet($offset, $value)
    {
        // 面倒なのでイテレータは変更不可。
        throw new BadMethodCallException;
    }

    public function offsetUnset($offset)
    {
        // 同様。
        throw new BadMethodCallException;
    }

    // - ArrayAccess }}}
    // {{{ Countable

    public function count()
    {
        return count($this->values);
    }

    // - Countable }}}
    // {{{ SeekableIterator

    public function current()
    {
        if (!$this->next) {
            throw new OutOfBoundsException;
        }
        return $this->next[1];
    }

    public function key()
    {
        if (!$this->next) {
            throw new OutOfBoundsException;
        }
        return $this->next[0];
    }

    public function next()
    {
        $this->next = each($this->values);
    }

    public function rewind()
    {
        reset($this->values);
        $this->next();
    }

    public function seek($position)
    {
        if (!array_key_exists($position, $this->values)) {
            throw new OutOfBoundsException;
        }
        $this->rewind();
        while ($this->key() != $position) {
            $this->next();
        }
    }

    public function valid()
    {
        return !!$this->next;
    }

    // - SeekableIterator }}}

    protected $next;
    protected $values;
}

?>

seek は非常に適当。まあ使わないだろうし別にいいや。