Пример использования ArrayAccess

Мне недавно в блоге задали вопрос о применении ArrayAccess. Просто как замену массивам — глупо, тем более теряется производительность. Итак, для этого у нас две основные причины — set/get должны как-то влиять на значение переменных, вторая — объект может использовать данные помещённые в нём для других методов.

Рассмотрим примеры. У нас есть класс для работы с таблице из базы данных как с объектом.

class User extends ArrayObject {
    function offsetSet($key, $value) {
        $value = mysql_escape_string($value);
        if ($key) {
            $this->array[$key] = $value;
        } else {
            $this->array[] = $value;
        }
    }
    function offsetGet($key) {
        if ( array_key_exists($key, $this->array) ) {
            return htmlspecialchars($this->array[$key]);
        }
    }
    function getHtml($key) {
        if ( array_key_exists($key, $this->array) ) {
            return $this->array[$key];
        }
    }
    function getFio() {
        return $this->array['firstName'] . ' ' . $this->array['lastName'] ;
    }
    // много много кода .........
}

Что бы сделали?
Изменили наш сэттер, теперь присвоенное значение можно смело вставлять в базу данных, не боясь sql injection. (это скорее силиконовый пример).
$user = new User();
$user[‘login’] = ‘test » evil code’;
$user->save();

Изменили геттер, чтобы данные можно было вставлять в шаблон, не боясь xss и проблем с поехавшей вёрсткой.
$user = new User(666);  //login -> <script>alert(‘HELP ME’);</script>
<p><?=$user[‘login’]?></p>

При этом с помощью специального опасного метода $user->getHtml(‘login’) мы имеем возможно вставлять и html код, но уже не позабыв об экранировании, а злонамеренно, чтобы навредить надоедливому заказчику :).

Ну и добавили новый метод, позволяющий получить сразу имя и фамилию $user->getFio().

Пример использования ArrayAccess: 9 комментариев

  1. fluid

    На мой взгляд использовать такой подход для работы с БД это сомнительное удовольствие:)
    На мой взгляд код
    $user = new User();
    $user[‘login’] = ‘test » evil code’;
    $user->save();
    не очень удобен, было бы удобнее пользоваться старым добрым сетом:
    $user = new User();
    $user->set(‘login’ ,’test » evil code’)
    ->set(‘password’,’123123′)
    ->save();
    А вот для класса Registry и т.п. такой подход довольно удобен..

    1. admin Автор записи

      я же написал как раз, что силиконовый пример, он не подходит во многом благодаря тому, что мы получим не тот результат при get
      $user[‘login’] = «test ‘ evil code»;
      echo $user[‘login’]; // вернёт «test \’ evil code

      1. fluid

        Оу да.. не обратил внимание… А так в целом довольно просто и понятно)

        ps А ты так всегда вредишь «надоедливому заказчику»? ;)

      2. admin Автор записи

        скорее надоедливым программистам ;)
        define(‘true’, false) — счастливого дебагинга.

  2. fluid

    не буду надоедать и не скажу, что вроде TRUE и есть константа, а их нельзя переопределять :))

    ps а идея хорошая:)

    1. sima

      Это с башорга)

      к вопросу о вчерашних скриптостраданиях. Только что кодер знакомый прислал, нашёл в коде программы, написанной уволенным коллегой незадолго до ухода:
      #define TRUE FALSE //счастливой отладки суки
      * ****** такого извращённого юмора ещё не встречал

      Пруф: _http://bash.org.ru/quote/268036

    1. AmdY Автор записи

      нет, это не равноценные конструкции, array_key_exists ищет ключ каким бы не было его значение, а isset ищет только если это значение не равно NULL.
      Если, чесно, я сам обычно пользуюсь isset или empty, т.к. в большинстве случаев важно именно значение хранящееся в переменной, а не тупо его наличие.

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

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