SPL в PHP: ArrayObject

Довольно неожиданно пришла идея довести начатый шаблонизатор до юзабельного вида, дописал хелперы, встроил кеширование, решил прицепить хелпер для формы. И здесь мне стало нехватать ООП стиля. Накидав кой-чего понял что вначале нужно написать цикл статей о SPL (Стандартной PHP библиотеке). Эта штука очень полезна при ООП стиле кодирования, а особо нормальных статей об SPL на русском я не обнаружил.

Начнёмс.

ArrayObject — предназначен для того, чтобы объект вёл себя как массив, даёт доступ к данным через квадратные скобки и позволяет делать foreach

ArrayObject implements IteratorAggregate , Traversable , ArrayAccess , Countable {
    /* Methods */
    ArrayObject::__construct ( mixed $input )
    void ArrayObject::append ( mixed $newval )
    int ArrayObject::count ( void )
    ArrayIterator ArrayObject::getIterator ( void )
    bool ArrayObject::offsetExists ( mixed $index )
    mixed ArrayObject::offsetGet ( mixed $index )
    void ArrayObject::offsetSet ( mixed $index , mixed $newval )
    void ArrayObject::offsetUnset ( mixed $index )
}

Данный класс имплементирует интерфейсы IteratorAggregate , Traversable , ArrayAccess , Countable

IteratorAggregate , Traversable — отвечают за гуляние по объекту, соответственно нужно реализовать метод getIterator. Эти вещи будем разбирать в другой раз.

Countable — нужно реализовать интерфейс для получения размера count.

ArrayAccess — это  квадратные скобочки — проверка существования offsetExists, получение значения — offsetGet, присвоение значения — offsetSet, уничтожение элемента — offsetUnset и добавление элемента — append.

Со скучной теорией покончено, сейчас практика

class Amdy_Array extends ArrayObject {
    protected $array;
    public function __construct($array) {
        $this->array = $array;
    }
    public function append($value) {
        $this->array[] = $value;
    }
    function offsetSet($key, $value) {
        if ($key) {
            $this->array[$key] = $value;
        } else {
            $this->array[] = $value;
        }
    }
    function offsetGet($key) {
        if ( array_key_exists($key, $this->array) ) {
            return $this->array[$key];
        }
    }
    function offsetUnset($key) {
        if ( array_key_exists($key, $this->array) ) {
            unset($this->array[$key]);
        }
    }
    function offsetExists($offset) {
        return array_key_exists($offset, $this->array);
    }

    public function dump() {
        var_dump($this->array);
    }
}

Так мы побыстрому создали свой обработчик, унаследовав класс из SPL. Что же там происходит.

В конструктор передаётся сам массив, его можно передать и позже, но не важно. Данный массив мы загоняем во внутреннюю переменную $this->array, дальше, мы описываем,  как должны обрабатываться запросы к объекту как к массиву. Т.е. все запросы будут реально относиться в переменно $this->array. Можно и вовсе не заводить эту переменную, а работать с атрибутами класса, если в коде заменить $this->array, на get_class_vars($this), $this->{$k} и т.д.

Простой пример использования.

$array = new Amdy_Array(
    array(
        'test',
        'test1' => array(0,1,2,3),
        2,
        'test4' => 'test2 value'
    )
);
$array[] = 'test2222';
echo $array[0] . '<hr/>';
echo $array['test4'] . '<hr/>';
$array->dump();

PHP не стоит на месте, потому, кое-что уже изменилось, постоянно добавляются новые классы, методы и интерфейсы, чтобы не изобретать свои велосипеды.

Вам также может понравиться

About the Author: amdy

12 комментариев

  1. Прикольно!
    Но массивы не могут быть многомерными, ну в смысле многомерными они быть могут, но выглядит не совсем хорошо!
    $array[1] = new ArrayObject;
    $array[1][1] = ‘Ячейка 1:1’;

  2. В таком случае спасает рекурсия в конструкторе, в конечном итоге будет ещё и обёртка для строк и итератор, статью о котором я всё никак не могу дописать. Всё это очень пригодится для обработки входных данных из $_REQUEST

  3. class MyArrayObject extends ArrayObject
    {
    protected $array = array();

    public function __construct($array = array())
    {
    foreach ((array) $array as $key => $value)
    {
    if (is_array($value))
    {
    $this->array[$key] = new self($value);
    }
    else
    {
    $this->array[$key] = $value;
    }
    }
    }

    public function offsetGet($key)
    {
    if (array_key_exists($key, $this->array))
    {
    return $this->array[$key];
    }
    }

    public function offsetSet($key, $value)
    {
    if ($key)
    {
    $this->array[$key] = $value;
    }
    else
    {
    $this->array[] = $value;
    }
    }

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

    public function offsetExists($key)
    {
    return array_key_exists($key, $this->array);
    }

    public function append($value)
    {
    $this->array[] = $value;
    }

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

    public function getIterator()
    {
    return new ArrayIterator($this->array);
    }

    public function __toString()
    {
    return ‘Array’;
    }
    }

  4. Согласен, рекурсивный конструктор выглядит лучше, а вот об интерфейсе итератора статья уже в разработке, правда, с декабря :(.
    В __toString(), наверное, лучше бросать exception или уже делать implode

  5. Включил мозг и разобрался 🙂

    Опечатки: особо ноРмальных статей об SPL на русском я не обноружиЛ

    Жду новых статей об SPL.

    1. спасибо огромное, поправил эти и ещё парочку, как же тяжело было без проверки орфографии в opera, да ещё с моей грамотностью 🙁

    1. Когда, например, получаешь строку из БД как объект, и обращаешься к нему, как к массиву.

  6. хм, случайно наткнулся на твой блог (:

    а почему не так, раз уж ты ничего в поведении не меняешь?
    class Amdy_Array extends ArrayObject {
    public function __construct( … ) {
    // получаем откуда-то массив
    parent::__construct( $array );
    }


    }

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *