Хранение настроек в файле php
Как сохранить конфигурацию для веб-приложения, написанного на PHP?
Я видел, как люди используют .ini, basic .php и т. Д.
Кроме того, define() или простые глобальные переменные?
Большая часть информации, которую вы можете найти.
Кроме того, хороши ли базы данных для хранения конфигурации?
Не существует «наилучшего способа (tm)» для хранения конфигураций вашего приложения. На самом деле все зависит от вашего приложения, типа конфигураций, от того, как часто они могут / должны изменяться, и насколько легко вы хотите их изменить.
Некоторые люди используют для своих приложений полный одноэлементный (или статический) класс Config . Это выглядит примерно так (с разной степенью сложности):
Это удобно, потому что вы можете вызывать его где угодно в своем приложении с помощью Config::set() или Config::get() . Затем у вас есть центральное место, где настраивается все ваше приложение, и вы можете сделать его настолько сложным или простым, насколько захотите. Вы можете создавать резервные копии в базе данных, memcached и т. Д., Что угодно.
Это подводит меня к следующему. Использование базы данных подходит для вещей, которые необходимо изменять на лету и не обязательно иметь «начальную настройку». Примером могут служить функции настройки приложения сайта (например, валюта, цвет фона, изображение заголовка и т. Д.). Проблема здесь в том, что вам нужно загружать это каждый раз, когда страница загружается в вашем приложении. Чтобы решить эту проблему, вы можете использовать технологию кэширования среднего уровня (например, memcached, если хотите). Это было бы быстро, намного быстрее, чем база данных, но все же добавляло бы накладные расходы, потому что вам нужно загружать его при каждой загрузке страницы.
Самый быстрый и, следовательно, самый «сложный» способ изменить - использовать файл config.php или что-то подобное. В этом файле должны быть определения ключей массива $_GLOBALS или define() для значений, к которым вам необходим доступ во всем приложении. Это быстро, потому что он включен в запрос и жестко запрограммирован в PHP, поэтому все, что PHP должен сделать, - это интерпретировать файл - без сетевого ввода-вывода или каких-либо дополнительных накладных расходов, кроме минимальных накладных расходов, связанных с включением файла в ваш сценарий. В этих файлах PHP вы будете хранить такие вещи, как ваши учетные данные для подключения к MySQL, учетные данные для подключения к веб-службам и т. Д.
Для приложения, у которого много пользователей и много настроек, вам, вероятно, потребуется развернуть «гибрид» методов или придумать свои собственные. Для чего-то, что является просто стандартным развертыванием приложения, вы можете обойтись очень простым подходом типа config.php .
Я изменил код Джеймсом и Заку. Вот моя реализация. Когда значение ищется и, если оно существует, возвращается, в противном случае возвращается пустая строка. В этом случае уведомления отображаться не будут. Есть метод удаления. комментарии и форматирование кода.
Это то чем я занимаюсь.
Сначала я определяю общий класс Dataset , который я могу использовать для глобального хранилища данных:
Затем я определяю класс Config , расширяющий его, где я могу добавить методы, специфичные для этого класса.
Обратите внимание, что важно добавить правило protected static $_data = array(); к классу Config или любым другим дочерним классам, если вы не хотите, чтобы они использовали один и тот же массив.
ИМО, сегодня имеет смысл хранить данные конфигурации в файле JSON.
Некоторые преимущества JSON:
- встроенная поддержка многих языков программирования
- легко читается людьми
- легко читается для машин
- маленький размер файла
Форматы хранения: адаптеры
Как показывает практика, наиболее удобным для использующего кода, форматом представления конфигурации является древовидная структура. То есть всё тот же ассоциативный массив.
А вот для хранения могут быть удобны разные форматы. Опять-таки массив (как выше), xml, ini-файл или ещё что-то.
Так как хранение от представления мы уже отделили, хранить мы можем в чём угодно, никак не влияя этим на интерфейс. Единственное, что нужно, это преобразовывать выбранный формат хранения к древовидной структуре для доступа к ней (то есть использовать различные адаптеры для загрузки).
Один из примеров такого подхода: Zend_Config.
Хранение файла конфигурации в репозитории
При работе с git или mercurial репозиторием нужно придерживаться следующему правилу - не хранить реальные настройки приложения в репозитории. Добавлять в репозиторий только структуру файла конфигурации, так называемый скелет.
Это нужно сделать по следующим причинам:
- При хранении боевых настроек в репозитории они могут попасть не в те руки.
- Если вы работаете в команде, у каждого её члена должны быть свои индивидуальный настройки (например конфиг для подключения к базе данных на локальном компьютере).
Перейдём к практике. Создайте файл "config.sample.php". Скопируйте туда созержимое вашего файла конфигурации и удалите как минимум значения важных (в нашем случае - паролей).
Добавьте файл config.sample.php в репозиторий. А боевой файл конфигурации config.php не должен туда попадать, поэтому исключите его из индексации, добавив строчку в файл ".gitignore":
Каков наилучший способ хранения группы глобальных параметров для пользовательского PHP-приложения? Я работаю над личным проектом (на первый взгляд, действительно), и мне нужен метод хранения пар ключ-значение для записи общих настроек для приложения.
Вещи для хранения как …
- Глобальное имя веб-сайта.
- Тема (просто переменная или путь к теме)
- и т.д
Должен ли я просто держать их в одном столе? Если да, то каков наилучший способ запросить их у бункера? Помимо выполнения одного запроса для каждой желаемой настройки.
UPDATE: Да. A .ini или разбор включенного файла будет приятным, и я знаю, как это сделать. Но я хотел знать, какой будет лучший подход к их хранению в MySQL со всем остальным.
UPDATE2: Причина, по которой я спрашиваю об этом, также заключается в том, что я планирую, что многие из этих параметров могут изменяться через интерфейс администратора. Поэтому, если вы изменили название сайта, он будет обновлен сразу, и я решил, что лучше всего будет делать это через SQL, поэтому вам нужно будет установить внутри БД.
Solutions Collecting From Web of "Лучший способ сохранить настройки PHP-приложения?"
Вы думали о том, чтобы поместить их в файл .php и включить его на страницы, которые вам нужно использовать? Дайте переменным уникальное имя, чтобы избежать конфликтов имен.
Поскольку вы будете использовать их повторно в своем приложении PHP, это будет наиболее идеальным. Это также позволяет избежать необходимости делать вызовы базы данных, если вы должны хранить их в базе данных.
Интерфейс доступа
Напишем простейший класс для получения конфигурации:
$config = Config::get(); // в нужном месте
В отличии от предыдущего примера мы снизили подключения файла до одного раза, даже при множестве запросов конфигурации и избавили прикладной код от знания пути к файлу.
Но гораздо важнее другое: мы разделили хранение конфигурации и интерфейс доступа к ней. Код, читающий конфигурацию, не обременяет себя знаниями о том, где она лежит, в каком виде и какими путями (может быть достаточно сложными) формируется. Можно полностью изменить способ хранения — на прикладной код это не повлияет.
С этого момента вопросами хранения конфига можно заниматься не задумываясь о вопросах его использования и наоборот.
Массивчик
Теперь у нас всё в отдельном конфигурационном массиве и не засоряет глобальную область.
Можно ещё избавиться от вредных привычек и вспомнить, что ассоциативный массив позволяет нам по-человечески всё структурировать:
Теперь и глазу приятнее и можно работать не со всем массивом, а с его частями.
Пример кода:
Файл Json:
Класс PHP:
Загрузка файла Json:
Как на самом деле отметил @Roger Ng, принятый ответ на самом деле не работает. Проблема в том, что вы не можете использовать $this в статическом методе.
PHP: статическое ключевое слово - руководство
Я думал об этом следующим образом:
Я использую функцию Config::init() , чтобы создать конфигурацию по умолчанию, к которой нужно вернуться, и функцию Config::merge() , чтобы объединить конфигурации по умолчанию, например, с производственными значениями.
Итак, мой default_config.php может выглядеть следующим образом:
И мой config.php примерно так:
В фактическом коде я получу свои значения конфигурации точно так же, как это сделано в принятом ответе, написав Config::get('key') .
.ini - не лучший способ хранить конфиги, так как веб-сервер будет показывать их публике. Не делай этого.
Храните конфиги в .php файле. Вы можете использовать глобальные переменные, define () или обычные переменные. Define обычно является лучшим вариантом. Для большей безопасности поместите его за пределы общедоступного каталога.
Я обычно помещаю настройки базы данных в config.php, а все динамические настройки в базу данных. Все настройки, которые не сильно меняются, обычно хорошо помещаются в файл конфигурации. Как тропинки и т. Д.
Я не думаю, что есть лучший способ, у каждого метода есть свои преимущества и недостатки. Просто убедитесь, что файл конфигурации (особенно если он содержит пароли) недоступен в общедоступном каталоге, а находится где-то в частном порядке.
Сохранение конфигурации в базе данных может работать, но вам все равно нужно где-то хранить информацию о подключении к базе данных, чтобы получить подключение. Я лично никогда не был поклонником этого метода. Единственным преимуществом будет простое онлайн-изменение значений элементов конфигурации или, например, конфигурация на уровне пользователя.
Использование define(); создаст константы, значения которых нельзя изменить во время выполнения. В некоторых случаях это работает, в других - нет. Если вы хотите, чтобы ваша конфигурация была доступна повсюду - в каждой области - вы можете рассмотреть возможность считывания конфигурации в класс (возможно, шаблон Singleton?), Чтобы вы могли получить доступ к значениям конфигурации везде.
Я использовал включенный файл php, файлы .ini, файлы XML и файлы JSON для конфигурации, лично я предпочитаю избегать файлов конфигурации .php, поскольку я делюсь своими файлами конфигурации на нескольких языках для разных приложений в своих веб-приложениях и придерживаюсь с другими «стандартами».
Наверное, все, кто сталкивался с разработкой более или менее серьезных приложений, знают, что выбор формата хранения настроек скрипта или приложения — достаточно ответственное дело. Конфиги должны быть легко читаемыми, легко модифицируемыми, легко переносимыми, и так далее — список можно продолжать и продолжать.
- INI-файлы
- PHP-скрипты
- XML-файлы
- Текстовые файлы
- Файлы с сериализованными данными
- Вне конкурса — PHP-скрипты с define'ами
- JSON-файлы NEW!
- Как можно быстрее загрузить настройки из файла
- Вернуть массив настроек в виде «ключ» => «значение»
- Конфигурационный файл содержит 10, 100 или 1000 конфигурационных параметров, представляющих собой короткие строки
- Конфигурация читается 1000 раз подряд, замеряется время работы в секундах
Конфигурацию оборудования не привожу. Понятно, что скорость скриптов зависит от сервера, но в данном случае сравниваются скрипты, а не серверы.
Правда, необходимо сделать небольшое уточнение по поводу программного обеспечения сервера. Использовался реальный веб-сервер, в момент низкой загрузки. Соответственно, конфигурация сервера «боевая»: Linux Debian Lenny, много памяти и RAID1-массив жестких дисков. PHP серии 5.2.x (не самый последний, врочем) с eAccelerator'ом. На время тестов отключался Zend Optimizer, чтобы тесты были более «чистыми», что минимально повлияло на результаты. Тесты без eAccelerator тоже проводились, но, как ни странно, сильно на распределение сил это не повлияло. Причина, на мой взгляд, кроется в том, что eAccelerator настроен на дисковое кэширование опкодов PHP и на сравнение времени модификации файлов, что «съедает» определенное количество времени — хотя и приносит определенные бонусы.
INI-файлы
Результаты: 0.015, 0.086, 0.784
Пример:
x1 = 1
x2 = 2
x3 = 3
Скрипт:
function config ( $file ) <
return parse_ini_file ( $file );
>
Конфигурационный файл с классическим, всем знакомым синтаксисом. Достаточно быстрый и удобный способ.
PHP-скрипты
Результаты: 0.029, 0.111, 0.902
Пример:
return array (
'x1' => '1',
'x2' => '2',
'x3' => '3',
);
?>
Скрипт:
function config ( $file ) <
return include ( $file );
>
Сначала маленькая оговорка. Во многих проектах конфигурационный файл не делает return, а просто определяет элементы глобального массива настроек. Это, с одной стороны, не совсем подходило под условия теста, а с другой стороны не совсем идеологически корректно в рамках борьбы против глобальных переменных. Поэтому для сравнения был использован предложенный вариант.
Обратите внимание на то, что этот вариант стабильно проигрывает INI-файлам, хоть и не очень значительно. Что ж, это компенсируется тем, что в настройках можно использовать PHP-выражения, что позволяет сделать конфиги максимально гибкими.
XML-файлы
Результаты: 0.062, 0.385, 3.911
Пример:
Скрипт:
function config ( $file ) <
$r = array ();
$dom = new DOMDocument ;
$dom -> load ( $file );
foreach ( $dom -> firstChild -> childNodes as $node ) <
if ( $node -> nodeType == XML_ELEMENT_NODE ) <
$r [ $node -> nodeName ] = $node -> firstChild -> nodeValue ;
>
>
return $r ;
>
Недостаток очевидный: очень маленькая скорость работы, в несколько раз медленнее, чем другие варианты. Чтобы проверить, не слишком ли медленная PHP-часть этого кода, я попробовал сделать return сразу после загрузки XML-документа (то есть, фактически, конфигурационные параметры не возвращались). Это ускорило процесс всего приблизительно в два раза. Что подтвердило общий вывод.
Результаты: NEW! 0.047, 0.276, 2.791
Скрипт: NEW!
function config ( $file ) <
$r = array ();
foreach ( simplexml_load_file ( $file ) as $k => $v ) <
$r [ $key ] = strval ( $v );
>
return $r ;
>
С помощью SimpleXML получается, конечно, быстрее. Но не настолько, чтобы претендовать на лидерство.
Текстовые файлы
Результаты: 0.034, 0.250, 2.369
Пример:
x1 1
x2 2
x3 3
Скрипт:
function config ( $file ) <
$r = array ();
if ( $F = fopen ( $file , "r" )) <
while (( $line = fgets ( $F )) !== false ) <
list ( $k , $v ) = explode ( "\t" , $line , 2 );
$r [ trim ( $k )] = trim ( $v );
>
fclose ( $F );
>
return $r ;
>
Не знаю, право, зачем этот способ существует. Возможно, его придумали до того, как изобрели parse_ini_file, или до того, как узнали об этой функции. Не сильно быстрый, не сильно удобный способ.
Результат: NEW! 0.036, 0.250, 2.213
Скрипт: NEW!
function config ( $file ) <
$r = array ();
foreach ( explode ( "\n" , file_get_contents ( $file )) as $line ) <
list ( $k , $v ) = explode ( "\t" , $line , 2 );
$r [ trim ( $k )] = trim ( $v );
>
return $r ;
>
Такой вариант реализации несколько медленнее для небольших файлов и быстрее для больших файлов. Но, в общем, не влияет на расстановку сил.
Файлы с сериализованными данными
Результаты: 0.011, 0.041, 0.309
Пример:
a:3:
Скрипт:
function config ( $file ) <
return unserialize ( file_get_contents ( $file ));
>
Наименее удобочитаемый конфигурационный файл — но при этом самый быстрый результат.
PHP-скрипты с define'ами
Результаты: 0.045, 0.252, 2.404
Пример:
define("x1", "1");
define("x2", "2");
define("x3", "3");
?>
Пример скрипта не привожу, потому что, как уже говорилось выше, результат в нужном виде вернуть достаточно сложно. Кроме этого, полученные результаты носят условный характер, поскольку второй раз define не переопределяет значение константы.
JSON-файлы NEW!
Результаты: 0.015, 0.057, 0.495
Пример:
Скрипт:
function config ( $file ) <
return json_decode ( file_get_contents ( $file ) , true );
>
JSON ворвался в нашу жизнь. Его реализация в PHP позволила даже обогнать одного из лидеров, INI-файлы, но немного уступает встроенной сериализации PHP. Одно замечание: приведенный код возвращает не массив, а stdClass object.
Выводы
Если Вы серьезный человек — то избегайте прямого чтения текстовых файлов, особенно с большими объемами. Вместо этого Вам вполне подойдут JSON-файлы или INI-файлы, тем более, что скрипты станут работать быстрее.
Если нужны гибкие настройки, с возможностью применения условий и переменных — то пишите конфигурационный файл на PHP. Работать будет медленнее предыдущих способов, но гибкость настроек в других способах недостижима.
Настройки в формате XML — самые медленные. Прежде, чем их использовать, подумайте хорошенько.
Искренне надеюсь, что define'ы никто не использует, поэтому оставляем их обсуждение вне выводов.
Итак, что же применить в реальном приложении? Само собой напрашивается применение комбинированного способа хранения настроек. Например, настройки хранятся в виде PHP-скрипта, результаты выполнения которого кэшируются в виде сериализованного массива. Использование такого подхода вместо чтения конфигурационного файла на PHP позволило получить следующие результаты:
Результаты: 0.018, 0.046, 0.317
Оптимально с точки зрения гибкости и скорости, на мой взгляд.
А вот и сам скрипт:
function config ( $file ) <
$file_dat = "$file.dat" ;
if (! file_exists ( $file_dat ) || filemtime ( $file_dat ) filemtime ( $file )) <
$r = include ( $file );
if ( $F = fopen ( $file_dat , "w" )) <
fwrite ( $F , serialize ( $r ));
fclose ( $F );
>
> else <
$r = unserialize ( file_get_contents ( $file_dat ));
>
return $r ;
>
Еще раз повторю, что подобные ухищрения могут быть полезны только в приложениях, которые запускаются часто и, соответственно, часто читают конфигурационные файлы.
P.S. PHP-код в статье не самый хороший. Я писал его, преследуя две цели: краткость и скорость работы. Поэтому отсутствуют комментарии, длинные имена переменных и различные проверки. Кроме того, большая часть кода работает под PHP 4 и 5 без проблем (кроме, конечно, XML). Надеюсь, это не вызовет излишнего накала страстей.
P.P.S. В сравнение добавлен код JSON.
P.P.P.S. Добавлены небольшие ремарки по поводу железа и программного обеспечения. Без них, согласен с авторами комментариев, было как-то не так.
Самый оптимальный вариант хранения настроек php приложения. В примерах для начинающих разработчиков, конфигурация приложения задаётся в начале исполняемого файла. Но для серьёзного Web приложения с множеством настроек такой вид конфигурации не удобен.
Рассмотрим на простом примере как оптимизировать хранение настроек приложения.
Создадим файл index.php со следующим содержимым:
Мы видим 2 группы переменных: первая для подключения к базе данных, а вторая для отправки письма по smtp протоколу. Избавимся от многочисленных переменных, объединив все значения в один многомерный ассоциативный массив.
Уже лучше. В современных Web приложениях конфигурацию принято хранить в отдельном файле / файлах. Давайте создадим файл config.php, перенесём туда наш массив и подгрузим его в index.php
Подключать будем с помощью конструкциии require, использовав её полезную особенность - возможно выполнить выражение return внутри включаемого файла. Делать это нужно следующим образом:
В файле конфигурации мы сделали return нашего массива. А в index.php присвоим этот массив переменной $config, используя выражение require.
С помощью print_r выведем результат. Вот что у нас получилось:
Если конфиг слишком большой, разбивать его на несколько файлов и собирайте с помощью require.
P.S. Что хранить в конфиге
В конце вводной части задумаемся над тем, что вообще следует хранить в конфигурации сайта, а что не следует.
Вот такого вот делать не надо:
Потребуется что-то изменить, перенести на другой сервер, скопировать на локалку: о такое можно убиться.
Все значения, которые можно сгенерировать на основании какого-то базового, лучше генерировать:
$dir_root = '/www/site.ru/htdocs'; $dir_image = $dir_root.'/image'; // Или шаблон вида ">/image", который вычислять в нужном месте. $dir_thumbs = $dir_image.'/thumbs'; $dir_css = $dir_root.'/css';
Базовое значение в примере, также в большинстве случаев можно получить автоматически на основании $_SERVER['DOCUMENT_ROOT'] или dirname(__FILE__) .
Не надо пытаться конфигурировать каждую мелочь: лишней работы вы и те, кто придут после вас, получите гарантированно, а лишняя гибкость пригодится далеко не всегда.
Для начала, пожалуй хватит. В следующей части поговорим о более интересных вещах.
18 комментариев »
В питоне все прикольнее, например имеем settings.py:
DATABASE_NAME = ‘name’
DATABASE_USERNAME= ‘username’
DATABASE_USERNAME= ‘password’
и юзаем где надо:
import settings
или
from settings import DATABASE_NAME, DATABASE_USERNAME
и т.д.
Мне такой способ хранения конфигов куда больше нравится :)
Не вижу особой разницы, если честно.
А в следующей статье напишу вещи чуть посложнее, расскажешь как такое в питоне сделать.
Я о том, что не надо никаких зендконфигов и прочей мутни… И это не (супер)глобальные переменные и т.д.
Спасибо, порадовал. По большей части так и делаю, видимо я на правильном пути :) .
phpdude, чего прижал? Поржал?
artoodetoo, я в тебе и не сомневался :)
интересно как хранить настройки для всего сайта и реврайтить некоторые для поддоменов, например…?
Бля, Вася_ц, пароль «qwerty» — это же просто трындец, сайты твои поломают на раз-два-три. Поменяй на что-то путевое!
Givi, сломай, дам пирожок )
>интересно как хранить настройки для всего сайта и реврайтить некоторые для поддоменов, например…?
не понял
>не понял
ну заходит юзверь на поддомен, а там функционал на другой СУБД висит…
kostyl, в следующей статейке четай.
vasa_c,
Вы рекомендуете использовать формат return array( … );
и далее пишите «Все значения, которые можно сгенерировать на основании какого-то базового, лучше генерировать:»
Подскажите как объединить выше написанное?
На примере следующего файла конфигурации:
$CONFIG = array(
‘a’ => «1»,
‘b’ => «2»,
‘ab’ => $CONFIG[‘a’].$CONFIG[‘b’],
);
2. В случае с путями, обычно получается построить вокруг __DIR__.
3. Я же люблю шаблоны:
return array(
'a' => 1,
'b' => 2,
'ab' => '>->',
);
В коде уже обрабатывать.
vasa_c, спасибо за идеи! Для моей текущей задачи воспользуюсь полухаком.
Я тоже часто пользуюсь полухаками, благо до return можно производить работу…
Не ожидал увидеть такого слаженного решения рассматриваемого вопроса.
Автору респект. :)
Константы
define('DB_HOST', 'localhost'); define('DB_USER', 'vasa'); // .
Теперь мы загадили глобальный контекст неоднородными, неструктурированными константами. Единственная радость: они доступны в любой области видимости и их нельзя случайно изменить.
Имея небольшое преимущество перед глобальными переменными, в некоторых случаях константы даже хуже них.
ОБНОВИТЬ:
Я предполагаю, что вы хотите, чтобы эти параметры были доступны для редактирования через веб-страницу и не нуждались в нескольких запросах БД, поскольку эти параметры будут меняться, но не слишком часто?
Один из подходов, который я лично принял, – это сериализовать таблицу AppSettings и сохранить ее в XML файле. Конечно, каждый раз, когда таблица обновляется, таблица будет ресериализована и сохранена в XML-файле. Затем я создал отдельный класс, который анализирует XML-файл и возвращает нужные мне значения.
Для одного, небольшого, простого сайта я просто установил конфигурацию в файл PHP. Будь проще. PHP, вероятно, не разбирает ничего быстрее, чем анализирует PHP. Если вы используете APC, скомпилированный байт-код даже кэшируется – хотя байт-код затем повторно выполняется для каждого запроса. Для небольшого файла конфигурации это выполнение байт-кода должно занимать очень мало времени; для очень большого файла это может занять немного больше времени.
Для сайтов с высоким трафиком с большими конфигурациями рекомендуется кэшировать ваши данные конфигурации в APC (например, в виде единого массива) – по крайней мере, вы сохраняете накладные расходы на выполнение операторов в файле config.php. Примечательно, что facebook делает это. Когда вы подаете много запросов в секунду, при каждом нажатии запроса на чтение файла конфигурации (с использованием parse_ini_file, анализатора XML и т. Д.) На каждый запрос не может быть и речи.
Для моего текущего проекта у нас есть много сайтов, каждый со своей собственной конфигурацией. На каждом сайте были и база данных, и файл конфигурации; однако, убедитесь, что вы всегда используете правильный файл конфигурации с правильной базой данных, которая может стать головной болью. Кроме того, изменения потребуют изменения вещей в двух местах – db и config. Забывание того или другого всегда вызывало проблемы, и это случалось слишком часто.
Мы переместили конфигурацию в базу данных, так что вы не можете отделить db от правильной конфигурации, и для любых изменений кода требуется только обновление базы данных. Данные из таблицы config также агрессивно кэшируются в APC, поэтому мы запрашиваем его редко.
- Маленький сайт : просто используйте файл config.php
- Очень большой сайт : кеш в APC
- Несколько сайтов : сохранить конфигурацию в базе данных, чтобы уменьшить административные издержки; кэш в APC для уменьшения ударов базы данных
Мы просто используем
В включенном файле php. Ввод значений в массив помогает с конфликтами имен.
Я понимаю, что вы хотите хранить вещи в таблице mysql, однако это, вероятно, означает сохранение требуемой конфигурации в нескольких местах. например, я уверен, что вам понадобится сервер базы данных и имя, хранящиеся в какой-либо строке. это означает, что они помещаются в файл include или .ini, поскольку вы не можете их прочитать из базы данных (как вы можете подключиться к базе данных, не зная об этом). так что вы будете хранить информацию о подключении db в файле include или .ini и остальных настройках базы данных? это работает, я полагаю, но мне нравится сохранять все настройки в одном файле (config.php или application.ini или что-то еще). это упрощает обслуживание imo.
Просто об этом поговорили с несколькими людьми в IRC. Я посмотрел, как WordPress справился с этим после того, как я вытащил SQL-дамп одной копии. Я думаю, что я буду использовать этот макет и немного переименовать столбцы. Но идея …
Обычно я в файле index.php настраиваю «необходимые» настройки так:
и в моем файле конфигурации:
Достойный подход состоял бы в том, чтобы получать обычно используемые настройки один раз на страницу через базу данных. Что-то вроде сохранения поля autoload bool, которое проверяет, должен ли параметр загружаться со страницей. Для других, гораздо менее привычных настроек вы можете получать их по воздуху.
Если вы решите кэшировать их все, а не извлекать для каждой страницы, вы можете подумать о способе уведомления сценария о перезагрузке настроек – или вам придется вручную сообщить об этом, чтобы вы этого не сделали застрял со старыми настройками после изменения некоторых.
Сегодня заведём разговор на такую, казалось бы простую, тему, как конфигурация сайта. То есть поговорим о таких вещах, как параметры подключения к БД, различные настройки, как всё это хранить и как со всем этим работать.
Разобьём этот разговор на три части:
- В текущей рассмотрим различные варианты организации конфига. Эта часть в первую очередь ориентирована на новичков.
- Во второй задумаемся над более сложными вещами. Например, как поддерживать набор отличающихся конфигов для одной системы.
- А в третьей части попробуем всё это высечь в коде.
Итак, где же можно хранить настройки системы?
Пример кода:
Файл Json:
Класс PHP:
Загрузка файла Json:
Как на самом деле отметил @Roger Ng, принятый ответ на самом деле не работает. Проблема в том, что вы не можете использовать $this в статическом методе.
PHP: статическое ключевое слово - руководство
Я думал об этом следующим образом:
Я использую функцию Config::init() , чтобы создать конфигурацию по умолчанию, к которой нужно вернуться, и функцию Config::merge() , чтобы объединить конфигурации по умолчанию, например, с производственными значениями.
Итак, мой default_config.php может выглядеть следующим образом:
И мой config.php примерно так:
В фактическом коде я получу свои значения конфигурации точно так же, как это сделано в принятом ответе, написав Config::get('key') .
.ini - не лучший способ хранить конфиги, так как веб-сервер будет показывать их публике. Не делай этого.
Храните конфиги в .php файле. Вы можете использовать глобальные переменные, define () или обычные переменные. Define обычно является лучшим вариантом. Для большей безопасности поместите его за пределы общедоступного каталога.
Я обычно помещаю настройки базы данных в config.php, а все динамические настройки в базу данных. Все настройки, которые не сильно меняются, обычно хорошо помещаются в файл конфигурации. Как тропинки и т. Д.
Я не думаю, что есть лучший способ, у каждого метода есть свои преимущества и недостатки. Просто убедитесь, что файл конфигурации (особенно если он содержит пароли) недоступен в общедоступном каталоге, а находится где-то в частном порядке.
Сохранение конфигурации в базе данных может работать, но вам все равно нужно где-то хранить информацию о подключении к базе данных, чтобы получить подключение. Я лично никогда не был поклонником этого метода. Единственным преимуществом будет простое онлайн-изменение значений элементов конфигурации или, например, конфигурация на уровне пользователя.
Использование define(); создаст константы, значения которых нельзя изменить во время выполнения. В некоторых случаях это работает, в других - нет. Если вы хотите, чтобы ваша конфигурация была доступна повсюду - в каждой области - вы можете рассмотреть возможность считывания конфигурации в класс (возможно, шаблон Singleton?), Чтобы вы могли получить доступ к значениям конфигурации везде.
Я использовал включенный файл php, файлы .ini, файлы XML и файлы JSON для конфигурации, лично я предпочитаю избегать файлов конфигурации .php, поскольку я делюсь своими файлами конфигурации на нескольких языках для разных приложений в своих веб-приложениях и придерживаюсь с другими «стандартами».
Наверное, все, кто сталкивался с разработкой более или менее серьезных приложений, знают, что выбор формата хранения настроек скрипта или приложения — достаточно ответственное дело. Конфиги должны быть легко читаемыми, легко модифицируемыми, легко переносимыми, и так далее — список можно продолжать и продолжать.
- INI-файлы
- PHP-скрипты
- XML-файлы
- Текстовые файлы
- Файлы с сериализованными данными
- Вне конкурса — PHP-скрипты с define'ами
- JSON-файлы NEW!
- Как можно быстрее загрузить настройки из файла
- Вернуть массив настроек в виде «ключ» => «значение»
- Конфигурационный файл содержит 10, 100 или 1000 конфигурационных параметров, представляющих собой короткие строки
- Конфигурация читается 1000 раз подряд, замеряется время работы в секундах
Конфигурацию оборудования не привожу. Понятно, что скорость скриптов зависит от сервера, но в данном случае сравниваются скрипты, а не серверы.
Правда, необходимо сделать небольшое уточнение по поводу программного обеспечения сервера. Использовался реальный веб-сервер, в момент низкой загрузки. Соответственно, конфигурация сервера «боевая»: Linux Debian Lenny, много памяти и RAID1-массив жестких дисков. PHP серии 5.2.x (не самый последний, врочем) с eAccelerator'ом. На время тестов отключался Zend Optimizer, чтобы тесты были более «чистыми», что минимально повлияло на результаты. Тесты без eAccelerator тоже проводились, но, как ни странно, сильно на распределение сил это не повлияло. Причина, на мой взгляд, кроется в том, что eAccelerator настроен на дисковое кэширование опкодов PHP и на сравнение времени модификации файлов, что «съедает» определенное количество времени — хотя и приносит определенные бонусы.
INI-файлы
Результаты: 0.015, 0.086, 0.784
Пример:
x1 = 1
x2 = 2
x3 = 3
Скрипт:
function config ( $file ) <
return parse_ini_file ( $file );
>
Конфигурационный файл с классическим, всем знакомым синтаксисом. Достаточно быстрый и удобный способ.
PHP-скрипты
Результаты: 0.029, 0.111, 0.902
Пример:
return array (
'x1' => '1',
'x2' => '2',
'x3' => '3',
);
?>
Скрипт:
function config ( $file ) <
return include ( $file );
>
Сначала маленькая оговорка. Во многих проектах конфигурационный файл не делает return, а просто определяет элементы глобального массива настроек. Это, с одной стороны, не совсем подходило под условия теста, а с другой стороны не совсем идеологически корректно в рамках борьбы против глобальных переменных. Поэтому для сравнения был использован предложенный вариант.
Обратите внимание на то, что этот вариант стабильно проигрывает INI-файлам, хоть и не очень значительно. Что ж, это компенсируется тем, что в настройках можно использовать PHP-выражения, что позволяет сделать конфиги максимально гибкими.
XML-файлы
Результаты: 0.062, 0.385, 3.911
Пример:
Скрипт:
function config ( $file ) <
$r = array ();
$dom = new DOMDocument ;
$dom -> load ( $file );
foreach ( $dom -> firstChild -> childNodes as $node ) <
if ( $node -> nodeType == XML_ELEMENT_NODE ) <
$r [ $node -> nodeName ] = $node -> firstChild -> nodeValue ;
>
>
return $r ;
>
Недостаток очевидный: очень маленькая скорость работы, в несколько раз медленнее, чем другие варианты. Чтобы проверить, не слишком ли медленная PHP-часть этого кода, я попробовал сделать return сразу после загрузки XML-документа (то есть, фактически, конфигурационные параметры не возвращались). Это ускорило процесс всего приблизительно в два раза. Что подтвердило общий вывод.
Результаты: NEW! 0.047, 0.276, 2.791
Скрипт: NEW!
function config ( $file ) <
$r = array ();
foreach ( simplexml_load_file ( $file ) as $k => $v ) <
$r [ $key ] = strval ( $v );
>
return $r ;
>
С помощью SimpleXML получается, конечно, быстрее. Но не настолько, чтобы претендовать на лидерство.
Текстовые файлы
Результаты: 0.034, 0.250, 2.369
Пример:
x1 1
x2 2
x3 3
Скрипт:
function config ( $file ) <
$r = array ();
if ( $F = fopen ( $file , "r" )) <
while (( $line = fgets ( $F )) !== false ) <
list ( $k , $v ) = explode ( "\t" , $line , 2 );
$r [ trim ( $k )] = trim ( $v );
>
fclose ( $F );
>
return $r ;
>
Не знаю, право, зачем этот способ существует. Возможно, его придумали до того, как изобрели parse_ini_file, или до того, как узнали об этой функции. Не сильно быстрый, не сильно удобный способ.
Результат: NEW! 0.036, 0.250, 2.213
Скрипт: NEW!
function config ( $file ) <
$r = array ();
foreach ( explode ( "\n" , file_get_contents ( $file )) as $line ) <
list ( $k , $v ) = explode ( "\t" , $line , 2 );
$r [ trim ( $k )] = trim ( $v );
>
return $r ;
>
Такой вариант реализации несколько медленнее для небольших файлов и быстрее для больших файлов. Но, в общем, не влияет на расстановку сил.
Файлы с сериализованными данными
Результаты: 0.011, 0.041, 0.309
Пример:
a:3:
Скрипт:
function config ( $file ) <
return unserialize ( file_get_contents ( $file ));
>
Наименее удобочитаемый конфигурационный файл — но при этом самый быстрый результат.
PHP-скрипты с define'ами
Результаты: 0.045, 0.252, 2.404
Пример:
define("x1", "1");
define("x2", "2");
define("x3", "3");
?>
Пример скрипта не привожу, потому что, как уже говорилось выше, результат в нужном виде вернуть достаточно сложно. Кроме этого, полученные результаты носят условный характер, поскольку второй раз define не переопределяет значение константы.
JSON-файлы NEW!
Результаты: 0.015, 0.057, 0.495
Пример:
Скрипт:
function config ( $file ) <
return json_decode ( file_get_contents ( $file ) , true );
>
JSON ворвался в нашу жизнь. Его реализация в PHP позволила даже обогнать одного из лидеров, INI-файлы, но немного уступает встроенной сериализации PHP. Одно замечание: приведенный код возвращает не массив, а stdClass object.
Выводы
Если Вы серьезный человек — то избегайте прямого чтения текстовых файлов, особенно с большими объемами. Вместо этого Вам вполне подойдут JSON-файлы или INI-файлы, тем более, что скрипты станут работать быстрее.
Если нужны гибкие настройки, с возможностью применения условий и переменных — то пишите конфигурационный файл на PHP. Работать будет медленнее предыдущих способов, но гибкость настроек в других способах недостижима.
Настройки в формате XML — самые медленные. Прежде, чем их использовать, подумайте хорошенько.
Искренне надеюсь, что define'ы никто не использует, поэтому оставляем их обсуждение вне выводов.
Итак, что же применить в реальном приложении? Само собой напрашивается применение комбинированного способа хранения настроек. Например, настройки хранятся в виде PHP-скрипта, результаты выполнения которого кэшируются в виде сериализованного массива. Использование такого подхода вместо чтения конфигурационного файла на PHP позволило получить следующие результаты:
Результаты: 0.018, 0.046, 0.317
Оптимально с точки зрения гибкости и скорости, на мой взгляд.
А вот и сам скрипт:
function config ( $file ) <
$file_dat = "$file.dat" ;
if (! file_exists ( $file_dat ) || filemtime ( $file_dat ) filemtime ( $file )) <
$r = include ( $file );
if ( $F = fopen ( $file_dat , "w" )) <
fwrite ( $F , serialize ( $r ));
fclose ( $F );
>
> else <
$r = unserialize ( file_get_contents ( $file_dat ));
>
return $r ;
>
Еще раз повторю, что подобные ухищрения могут быть полезны только в приложениях, которые запускаются часто и, соответственно, часто читают конфигурационные файлы.
P.S. PHP-код в статье не самый хороший. Я писал его, преследуя две цели: краткость и скорость работы. Поэтому отсутствуют комментарии, длинные имена переменных и различные проверки. Кроме того, большая часть кода работает под PHP 4 и 5 без проблем (кроме, конечно, XML). Надеюсь, это не вызовет излишнего накала страстей.
P.P.S. В сравнение добавлен код JSON.
P.P.P.S. Добавлены небольшие ремарки по поводу железа и программного обеспечения. Без них, согласен с авторами комментариев, было как-то не так.
Самый оптимальный вариант хранения настроек php приложения. В примерах для начинающих разработчиков, конфигурация приложения задаётся в начале исполняемого файла. Но для серьёзного Web приложения с множеством настроек такой вид конфигурации не удобен.
Рассмотрим на простом примере как оптимизировать хранение настроек приложения.
Создадим файл index.php со следующим содержимым:
Мы видим 2 группы переменных: первая для подключения к базе данных, а вторая для отправки письма по smtp протоколу. Избавимся от многочисленных переменных, объединив все значения в один многомерный ассоциативный массив.
Уже лучше. В современных Web приложениях конфигурацию принято хранить в отдельном файле / файлах. Давайте создадим файл config.php, перенесём туда наш массив и подгрузим его в index.php
Подключать будем с помощью конструкциии require, использовав её полезную особенность - возможно выполнить выражение return внутри включаемого файла. Делать это нужно следующим образом:
В файле конфигурации мы сделали return нашего массива. А в index.php присвоим этот массив переменной $config, используя выражение require.
С помощью print_r выведем результат. Вот что у нас получилось:
Если конфиг слишком большой, разбивать его на несколько файлов и собирайте с помощью require.
База данных
Настройки можно хранить в базе данных (ну, кроме, собственно, параметров подключения к базе), а при необходимости, выбирать их оттуда запросами.
На первый взгляд это весьма забавное и имеющее право на существование решение. Тем более, что многие популярные форумы и блоги используют его.
Но при более детальном рассмотрении, это самое идиотское, что можно придумать по этой теме. В базе можно хранить настройки, которые будут меняться через веб-интерфейс, а также настройки пользователей и т.п. Хранить там общую конфигурацию, это пиз.ц.
Такое решение обычно предполагается гибким, так как позволяет менять настройки через какую-нибудь админку, не имея доступа к коду (или не затрудняясь этим доступом). На деле для общих настроек это нахрен не нужно. Никому в жизни не понадобиться изменять путь к папке с темами для форума SMF. А если и понадобиться: ему всё равно придётся лезть в код и копировать эту папку на новое место.
Изменить что-то не предусмотренное в подобной админке, а тем более добавить новый параметр выливается во множество неприятных ощущений. А попытка скопировать себе сайт на локалку для разработке, превращается вообще во что-то мазохистское. После копирования нужно лезть в базу и выискивать там все параметры, которые необходимо изменить. Особенно радует, что хранятся они обычно в совершенно неудобоваримом формате.
Нигде не хранить
Можно вообще не напрягаться с отдельным хранением настроек, а использовать их напрямую в нужном месте:
mysql_connect('localhost', 'vasa', 'qwerty');
И так желательно сделать в каждом файле, где нужен доступ к базе. Тогда попытка изменить какой-то параметр обязательно превратиться в незабываемый праздник.
После использования данного подхода некоторое время на сайтах объёмом более трёх файлов, разработчики обычно понимают, что дальше так жить нельзя.
return array()
Не все знают, что обработку файла можно завершать, как и для функции, с помощью оператора return . Более того, из него можно возвращать значение, которое станет результатом include или require , которыми мы этот файл подключили.
Создадим файл конфигурации ( config.php , допустим):
Теперь у нас вообще никаких глобальных переменных нет. Конфиг перестал определять то, как его должен использовать программный код, а определяет только конфигурацию. А уже в коде в нужном месте:
$config = include('/path/to/config.php'); // Считываем конфигурацию из файла в переменную
Глобальные переменные
Первое что делают после осознания того, что настройки системы следует объявлять единожды и в одном месте:
Уже лучше, но есть и минусы. Те же самые, что и вообще у глобальных переменных. Загадили глобальный контекст неоднородными, неструктурированными данными. С областями видимости будут постоянные проблемы. А так как и вся система при таком конфиге, очевидно, будет построена на глобальных переменных, то встаёт вопрос конфликта имён со всеми неприятно вытекающими последствиями.
Улучшение интерфейса
Интерфейс доступа к конфигу (в прошлом примере это Config::get() ) можно улучшать бесконечно и по своему вкусу.
Убрать статику, а на объект навешать магических методов и SPL-интерфейсов, чтобы получилось что-то вроде:
$db_host = $config->db->host; $db_user = $config->db->user;
Получение config-объекта можно сделать через IoC-контейнер или через какую-нибудь другую заумную вещь.
По поводу улучшения интерфейса можно придумать много чего, а ещё больше можно найти готового в интернете. Оставим эту тему и в дальнейшем сконцентрируемся сугубо на способе хранения конфигурации.
Читайте также: