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

Комментарии 42

Позволю себе развернуть Вашу глубокую мысль выраженную столь лаконично.
Нормальный конфиг написан на языке с простим синтаксисом. И его очень просто проверить на корректность. А ежели конфиг написан на ЯП, то разобрать что там — это довольно сложно. Для «конфигов» которые предназначены для изменения только программистом такой метод вполне допустим. Только это уже будут не конфиги, а модули (или как оно называется в вашем языке). А давать конечным пользователям программы возможность писать такой «конфиг»-программный модуль — это весьма смелое, и не факт что разумное решение. При неверном конфиге, программа должна сообщить где там ошибка и почему, а не пытаться форматировать диск.
Несмотря на недостатки такой метод применяется в интерпретируемых языках типа PHP. Видимо, потому что это просто, а на ошибку в конфиге может укажет интерпретатор.
При наличии уже готовой инфраструктуры можно написать GUI, если предполагается изменение настроек пользователем, с автоматической генерацией самоинтерпретируемых файлов. В итоге пользователю не нужны знания по ЯП, а сгенерированный файл не нуждается в разборе.
чтобы этого не было нужно запускать программы от пользователя с ограниченными правами.
с некоторых пор этот функционал есть даже в windows.
JSON.
Идея не нова, могу навскидку назвать десяток CMS, которые таким образом хранят конфиги и иные данные.

В случае PHP особенно полезно использовать тот факт, что операторы типа include могут возвращать данные, то есть писать что-то типа:

$config = include(_CONFIG_ROOT. 'config.php');

это позволит Вам разделить области видимости и не «гадить» в глобальном пространстве имен.

Однако производительность такого подхода низка — на каждый файл будет запускаться своя копия интерпретатора.
Не знаю как в php но в perl'е я сначала читаю конфигурацию в строку, а потом делаю eval.
Это не одно и то же. Вы в Perl-е просто выполняете некий код в глобальном пространстве, а в PHP код выполняется в своем, а в глобальное может вернуть некое значение.
Any variables available at that line in the calling file will be available within the called file, from that point forward. However, all functions and classes defined in the included file have the global scope.

Не «некое значение», а «всё» возвращается в глобальное пространство.

А в Perl чтобы такого не случилось используются названия пакетов(package) и они вот как раз в определённой степени изолированы от основной программы.

И самое главное! eval в Perl можно выполнять и в лексической области видимости и в глобальной по желанию, так что, уважаемый, вы очень сильно заблуждаетесь.
Спасибо, просветили.
ini-файлы (и прочие универсальные форматы) все-таки более понятны и наглядны для неспециалистов в языке.

А для ускорения и прочих проверок лучше всегда достаточно кеширования в сериализованной или в языковой (генерация нативного кода на основании ini-файла) форме.
Если кэшировать ini в нативный PHP — ускорения никакого не будет. Проверено.

alexleonov.habrahabr.ru/blog/78976/
Хм, как насчет безопасности? такой «конфиг» все что угодно может сделать, ну его нафиг.
Интересно, при проектировании вы разделяете права доступа на скрипты и конфигурационные файлы?
Если у человека есть доступ к конфигам, то вероятнее всего у него есть доступ и к скриптам. А если нет разницы, то зачем «платить» больше? :-)
Не, ну, если Вы дадите пользователям править php-конфиги, то будут у Вас и проблемы с безопасностью, и с непонятками формата. По мне так конфигурационные файлы в любом виде не для пользователей.
Даёшь пользователям пользовательский интерфейс! :)
В общем резюмируя вашу мысль можно сказать просто — долой конфигурационные файлы (в классическом понимании).
Жаль, что из заметки был вынесен только такой смысл. На самом деле, целью было рассказать о концепции self-executable data. Конфигурационный файл был лишь одним примером из трех.
Конфигурационные файлы были для того и придуманы, чтоб отделить настройки от кода. С той же целью, к примеру, отделяют данные от представления. И почему я не удивлён, что идея хардкодить настройки в код, пришла в голову именно похапешнику?
Какой смысл от конфигурационного файла, если рука конечного пользователя до него не доберется?
Мы не будем рассматривать ситуацию, когда продукт коробочный и предназначен для «масс».

Не стоит это сравнивать с парой данные-представление.
Так или иначе настройки находящиеся в ini-файле или в любом другом виде, но не коде, необходимо разобрать и представить в каком-либо виде в коде. И то, что бизнес-логике конфигурация будет передаваться в виде того же объекта, описанного руками программиста или объекта, полученного при парсинге какого-либо «источника конфигурации», ни как на самой этой логике не отразится.
Про файлы конфигурации см. комментарий выше.
Насчет «пэхапэшника» — не уверен, что Вы хотели этим сказать, но должен заметить, что концепция компиляции данных пришла именно из системного программирования. Видели, например, как выглядит back-end оптимизирующего JIT-компилятора Sun Java SE (C2)? Он в основном состоит из одного файла — описания архитектуры процессора, в каком-то смысле именно конфигурационного файла. При этом описание сущностей (например, peephole optimizations) носит именно императивный характер, т.е. в виде алгоритма, как это будет работать. Пример с компиляцией шрифта — тоже реальный случай из системного программирования, где он сыграл большую роль в ускорении рендеринга текста в ПО мобильного телефона.
Это же классический антипаттерн.
Разделение данных и кода идет еще со времен Н.Вирта: «Алгоритмы+Структуры данных = Программы»

— Понял?
— Да.
Запомни, и никогда так не делай!: )
SFX-архивы, в таком случае, вообще несусветное зло: это ж какой изверг додумался все запихивать в один файл, а потом еще делать так, чтоб программа открывала сама себя как файл с данными!
Пусть SFX вас не смущает. Рассматривайте его как контейнер.
Вы же не ругаетесь, когда маунтите ISO-образ, а там… файлы! :)

С исходным кодом ситуация совсем другая.
Код нужно разбивать на части, чтобы упростить его понимание тем, кто будет [после вас] его поддерживать: читать и разбирать.
Данные отделяют от кода — это, пожалуй, самый древний паттерн. Может даже древнее MVC : )

А в скомпилированном/собранном виде программа вполне может быть и одним файлом — процессору пофигу.
Все верно: данные от кода надо отделять. Только для этого необязательно выдумывать отдельный язык описания данных, если многие современные объектно-ориентированные языки программирования и так предоставляют замечательные средства, чтобы изящно и понятно описывать самые разнообразные сущности. Благодаря инкапсуляции так и получается: в одном месте код: интерфейс и его программная реализация, а совершенно в другом — данные, описываемые с помощью классов.

Вспомните JSON — простое и гениальное, на мой взгляд, изобретение — как раз воплощение того, о чем я здесь писал. Да, были там проблемы и с безопасностью, но все эти трудности успешно разрешены, самоинтерпретируемая нотация широко и успешно применяется в настоящий момент.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
как-то не совсем понял, что сложного написать к обычному ini файлу, один единственный объект, который будет парсить и проверять этот ini на попавшую туда лабуду, а потом пользоваться им так же в одну строчку, но уже знать, что если туда, кто то что то запишет из другого места, ты проверишь эти данные на вход?
А чем Вам, собственно, стандартные методы не угодили?
Весь цивилизованный мир давно делает, например, так:
$multidim = true; // Размерность массива
$confg = parse_ini_file ( $filename, $multidim );


И ещё Вы, вероятно, забыли, что часть кода может быть люто обфусцирована либо вообще прикрыта Zend'ом. Со всеми вытекающими.
Можно написать класс-одиночку в конструкторе которого единожды распарсить конфиг, загнать его в какой-нибудь key-value кеш, и далее работать с этим классом, та же одна строчка получится с быстрым и удобным доступом к данным.
Задание настроек в конфигурационном файле является, по сути, формой программирования. Когда вы используете для конфигурирования специальный формат, типа ini, фактически вы используете простой DSL. Автор статьи предлагает выделить из языка общего назначения некоторое подмножество и использовать его для конфигурирования. Фаулер называет такие подмножества внутренним DSL: www.martinfowler.com/articles/languageWorkbench.html
О! А вот это по теме. Спасибо за ссылку, почитаю.
Да такое, собственно, происходит сплошь и рядом. Взять тот же lua, который, по сути, является очень продвинутым языком конфигураций.
На Питоне, думаю, выглядело бы красивее, чем на PHP:

config = {

    'Roga-Kopyta'dict(
        type = 'flash',
        width = 100,
        height = 100,
        src = 'roga-kopyta.swf',
        link = 'www.roga-kopyta.com'
    ),

    'SuperPuper'dict(
        type = 'image',
        width = 468,
        height = 60,
        src = 'superpuper.jpg',
        link = 'www.supper-pupper.net'
    )

}
Colored with dumpz.org

А уж про JSON и говорить нечего.
На меня нахлынуло сильное подозрение, что товарищ, сам того не подозревая, очень хочет перейти с пыха на лисп. Наверное созрел.

(def config 
     {"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"}})
Colored with dumpz.org

Самоинтерпретируемые конфиги… где-то я их уже видел… эмакс?

А вообще, да — на что только люди не пойдут, только чтоб на лиспе не писать.
Сама по себе идея хоть и не нова, но очень интересна своим удобством. Подобный подход применяется не в одном фреймворке, и с такими файлами работают в первую очередь программисты

использовать такой подход к файлам которые будут править люди далекие от программирования, имхо, нельзя
все таки ini более интуитивно понятнее
Я ожидал увидеть в статье как использовать конфигурационные файлы на интерпретируемом языке программирования в проектах на компилируемых языках (С++, например). А увидел следуещее: в проекте на пхп конфиги лежат в пхп-файлах.
Значит, неудача :) А если серьезно, то ничего хитрого и для C++ нет: берется ECMAscript engine с открытым кодом на нужном Вам языке — en.wikipedia.org/wiki/List_of_ECMAscript_engines, с использованием его API создаются обёртки для объектов, которые будут «видны» из скрипта — и все, можно исполнять Javascript-подобные сценарии из Вашей программы.
Кстати, когда-то давно я написал простенький парсер выражений на С++ (как раз для всякого рода конфигурационных файлов), постепенно он обрастал и усложнялся, пока не вырос в очень-похожий-на-ECMAscript язык с функциями, объектами, сборщиком мусора и всё такое :)
Так что могу поделиться и своим движком, если интересно. Пусть он и не полностью совместим с ECMA-262, зато по коду очень компактный и простой.
Во, напомнили: еще один пример самоисполняемых данных.
Традиционные интерпретаторы выглядят как большущий switch в цикле:
for (;;) {
  switch (next_bytecode()) {
    case CODE_0:
      ...
      break;
    case CODE_1:
      ...
      break;
    case CODE_N:
      ...
      break;
  }
}

А можно интерпретатор сделать проще и наглядней с самоисполняемым промежуточным представлением (IR). В моем случае это Control Flow Graph (CFG), вершинами которого служат экземпляры класса Instruction с виртуальным методом execute:

Instruction* instr = sequence();
while (instr != NULL) {
  instr = instr->execute();
}

class Instruction {
protected:
  Instruction* _next;

public:
  virtual Instruction* execute() {
    return _next;
  }
};

class Branch : public Instruction {
protected:
  Expression* _cond;
  Instruction* _true_branch;

public:
  virtual Instruction* execute() {
    return _cond->evaluate()->as_boolean() ? _true_branch : _next;
  }
};

и т.д.
Примеры уместного использования самоисполняемых структур можно придумывать бесконечно.
И, заметьте, ini файлы, на которых тут все зациклились, вообще ни при чем. Речь-то совсем о другом :)
Зарегистрируйтесь на Хабре, чтобы оставить комментарий