Как стать автором
Обновить
0

Самоинтерпретируемые данные работают за программиста

Время на прочтение5 мин
Количество просмотров4.2K
Как часто вы используете текстовые конфигурационные файлы вроде ini, cfg, rc, xml, properties? Пишете ли для них обработчики, которые парсят строки и интерпретируют команды?
А я предлагаю иначе — записывать конфигурации на скриптовом языке (PHP, JavaScript и др.), используя удобства объекто-ориентированного программирования.

Пример 1

Предположим, в файле banners.ini хранится информация о баннерах, которые нужно отобразить на веб-странице:

[Roga-Kopyta]
type = flash
width = 100
height = 100
src = roga-kopyta.swf
link = www.roga-kopyta.com

[SuperPuper]
type = image
width = 468
height = 60
src = superpuper.jpg
link = www.supper-pupper.net

Как правило, в этом случае требуется данные считать, проверить на корректность, разобрать и занести в массив для дальнейшей обработки. Так почему бы сразу не записать те же данные в виде готового массива?

$banners = array(
  // Roga-Kopyta
  array("type" => "flash",
        "width" => 100,
        "height" => 100,
        "src" => "roga-kopyta.swf",
        "link" => "http://www.roga-kopyta.com"),
  // SuperPuper
  array("type" => "image",
        "width" => 468,
        "height" => 60,
        "src" => "superpuper.jpg",
        "link" => "http://www.supper-pupper.net")
);

В наглядности код ничуть не потерял, но теперь зато входной файл не нужно парсить! Однако и это еще не все. Если пойти дальше, можно в том же файле сразу определить и поведение объекта, назначив ему класс-обработчик.

$banners[] = new FlashBanner(100, 100, "roga-kopyta.swf",
                             "http://www.roga-kopyta.com");
$banners[] = new ImageBanner(468, 60, "superpuper.jpg",
                             "http://www.supper-pupper.net");

Тем временем дочерние классы FlashBanner и ImageBanner будут описывать, чем отличаются эти типы баннеров при выводе на страницу. Более того, теперь вместо if'ов и switch'ей для анализа свойств будет лишь один вызов виртуального метода.

abstract class Banner {
  protected $width, $height, $src, $link;

  public function __construct($width, $height, $src, $link) {
    ...
  }

  public function display() {
    $html = $this->toHTML();
    ...
  }

  abstract public function toHTML();
}

class ImageBanner extends Banner {
  public function toHTML() {
    return "<a href='{$this->link}'><img src='{$this->src}' " .
           "width={$this->width} height={$this->height}'></a>";
  }
}

class FlashBanner extends Banner {
  public function toHTML() {
    return "<object>...</object>";
  }
}

После этого вся «обработка» конфигурационного файла сведется к паре строк:

include "banners.php";
foreach ($banners as $banner) {
  $banner->display();
}


Пример 2

А в наших проектах особую роль играют самоинтерпретируемые файлы, описывающие конфигурацию базы данных. Подключив такой конфигурационный файл, мы сразу получаем иерархию классов для всех таблиц со всеми полями, причем каждое поле, наследуя один из стандартных классов IntField, StringField, DateField и т.п., автоматически обретет методы для форматирования, для проверки на правильность ввода, для связи с другими таблицами и т.д.

class Table_users extends Table {
  function __construct {
    $this->fields["id"]        = new users_id();
    $this->fields["login"]     = new users_login();
    $this->fields["password"]  = new users_password();
    $this->fields["group"]     = new users_group();
    $this->fields["registred"] = new users_registred();
  }
}

class users_id extends IntField {
  public $flags = BasicField::PRIMARY_KEY;
}

class users_login extends StringField {
  public $size = 50;
}

class users_password extends StringField {
  public $size = 255;
}

class users_group extends IntField {
  public $foreignTable = "groups";
  public $foreignKey = "id";
}

class users_registred extends DateField {
  public $format = "d/m/Y";
}

...

class StringField extends BasicField {
  public function validate($value) {
    return is_string($value) && strlen($value) <= $this->size;
  }
  public function toHTML($value) {
    return htmlspecialchars($value);
  }
}

class DateField extends BasicField {
  public function validate($value) {
    ...
  }
  public function toHTML($value) {
    return date($this->format, $value);
  }
}


Пример 3

Данные в самоинтерпретируемый вид не обязательно должны приводиться вручную, и, разумеется, язык обработки данных может быть любым, вплоть до машинного кода. На прошлой работе у нас использовался довольно интересный способ оптимизировать формат хранения шрифтов для наискорейшего вывода текста на экран. Каждая буква шрифта компилировалась в набор машинных инструкций, рисующих точку или линию в нужной позиции. В итоге код на C для вывод строки выглядел примерно так:
  for (char* c = str; *c != 0; c++) {
    x += font[*c](x, y);
  }


Заключение

Представление данных в виде исполняющих конструкций языка программирования позволяет без потери наглядности существенно упростить механизм обработки этих данных, экономя на проверке корректности и разборе конструкций (которые выполняет сам сам транслятор языка программирования), а также на интерпретации данных и связи описания с поведением.

P.S. А заинтересованных в работе веб-программиста приглашаем сюда — habrahabr.ru/job/2277
Теги:
Хабы:
+2
Комментарии42

Публикации

Информация

Сайт
www.art.su
Дата регистрации
Дата основания
Численность
11–30 человек
Местоположение
Россия

Истории