Эта тема на forum.dklab.ru


Engel: Фаил конфигураций. Организация.
Добрый день.
Очень часто приходиться создавать файлы конфигураций, которые содержат хост, имя пользователя, пароль для БД и другие конфигурации. Можно, к примеру, все настройки определять отдельными переменными к примеру:

$db_host = 'localhost';
$db_user = 'myuser';
// etc


можно хранить в массиве

$CFG = array();
$CFG['db_host'] = 'localhost';
$CFG['db_user'] = 'myuser';
// etc


в тих примерах есть свои минусы один из них:
- любое значение можно изменить/удалить
(конечно есть ещё и другие)

Не знаю, лишено ли смысла использовать в этом случае класс с конфигурациями?
К примеру, чтобы получения некого параметра выглядело так:

echo "Мой сайт: ". Config::Get('host');

Решил сделать.
Получился небольшой класс, хотелось бы услышать мнения о его пригодности для использования.
класс объявлен как final чтобы нельзя было его наследовать, и переопределять свойства и методы, и конструктор клана объявлен приватным чтобы исключить возможность инстанцировать класс.
Обязательное условие: PHP5.

Получение свойств осуществляется так:

Config::Get('имя_свойста');

Сам класс:

final class Config
{
private $host = 'mysite.ru';
private $db_host = 'localhost';
private $db_name = 'mydb';
private $db_user = 'myuser';
private $db_password = 'secret';
// etc

private function __construct()
{
// чтобы нельзя было инстанцировать класс
}

public function Get( $param )
{
try {
$ref = new ReflectionProperty( __CLASS__ , $param );
}
catch( ReflectionException $e )
{
return null;
}

return $ref->getValue();
}

}


Спасибо.
Константин Жинько [tIT]:
- любое значение можно изменить/удалить
define()
Антон Макаренко:
Константы в любом случае. Только конфигу можно добавить немного интеллектуальности:
1) Изначально данные в конфиге определяются как массив, а в конце объявляются как константы

$CFG=array();

// editable area
// ...
$CFG['DATEFORMAT'] = 'd.m.Y H:i';
$CFG['ENCODING'] = 'windows-1251';
$CFG['LIBS'] = '/home/web/lib'; // Absolute path to libs directory
// ...

// non-editable area
if (!defined("PATH_SEPARATOR"))
define("PATH_SEPARATOR", getenv("COMSPEC")? ";" : ":");
ini_set("include_path", ini_get("include_path").PATH_SEPARATOR.$CFG['LIBS']);
// ...

// далее объявляются константы
foreach (array_keys($CFG) as $k)
define('CFG_'.$k, $CFG[$k]);
unset($CFG);


2) Можно задать несколько конфигураций и переключаться между ними. Удобно, если носиться между разными хостингами:

$configuration=1; // set configuration here
switch ($configuration)
{
case 1:
// general purpose
$CFG['DATEFORMAT'] = 'd.m.Y H:i';
$CFG['ENCODING'] = 'windows-1251';
$CFG['LIBS'] = 'D:/web/lib'; // Absolute path to libs directory
// smarty
$CFG['SMARTY_DATEFORMAT'] = '%Y.%m.%d %H:%M';
break;
case 2:
$CFG['DATEFORMAT'] = 'd.m.Y H:i';
$CFG['ENCODING'] = 'windows-1251';
$CFG['LIBS'] = '/home/web/lib';
$CFG['SMARTY_DATEFORMAT'] = '%Y.%m.%d %H:%M';
break;
}

Кстати, как бы оптимизировать код, чтобы и неискушенному админу было понятно, и чтобы изящно было?
Г.О.:

в тих примерах есть свои минусы один из них:
- любое значение можно изменить/удалить


Не понял? Зачем изменять/удалять?
Константин Жинько [tIT]:
Не понял? Зачем изменять/удалять?
Случайно
Г.О.:
"]
Г.О. писал(а):
Не понял? Зачем изменять/удалять?
Случайно


Случайно можно и винт форматнуть и еще много чего сделать. Я в массивах храню и ничего такого не случалось никогда. Одна конфигурация — один массив. А с константами их получается несколько. Если несколько баз используется, то тут еще большие трудности начинаются.
Anonymous:
Константы в любом случае.
Можно, только немного смущает засорение глобальной области кучей констант (особенно если параметров много)

Я в массивах храню и ничего такого не случалось никогда.
если разработчиков несколько и 2-ое случайно использовали одинаковый индекс в массиве...
Engel:
извиняюсь, это был я.
Антон Макаренко:
засорение глобальной области кучей констант
Правильно, нужно щепетильно относиться к множеству конфигурационных констант (именование, использование только при необходимости), чтобы глобальная область не засорялась.
p.s.
А еще константы как конфигурационные данные удобно использовать в Smarty -- получается наравне с суперглобальными массивами.
А еще Zend Code Analyzer рекомендует не использовать переменные в инклудах:

// dangerous
$script_path='/htdocs';
include($script_path.'/foo.inc');

// recommended
define('SCRIPT_PATH', '/htdocs');
include(SCRIPT_PATH.'/foo.inc');

Дмитрий Котеров:
Ну а я вот предпочитаю использовать http://php.net/parse_ini_file.
ml05:

final class Config
{
private $host = 'mysite.ru';
private $db_host = 'localhost';
private $db_name = 'mydb';
private $db_user = 'myuser';
private $db_password = 'secret';
// etc

private function __construct()
{
// чтобы нельзя было инстанцировать класс
}

public function Get( $param )
{
try {
$ref = new ReflectionProperty( __CLASS__ , $param );
}
catch( ReflectionException $e )
{
return null;
}

return $ref->getValue();
}

}
echo Config::Get('host');

Warning: ReflectionProperty::getValue() expects exactly 1 parameter, 0 given
php5.1.4

- public function Get( $param )
+ static public function Get( $param )
mot: Re: Фаил конфигураций. Организация.
Решил сделать.
Получился небольшой класс, хотелось бы услышать мнения о его пригодности для использования.
класс объявлен как final чтобы нельзя было его наследовать, и переопределять свойства и методы, и конструктор клана объявлен приватным чтобы исключить возможность инстанцировать класс.
Обязательное условие: PHP5.

Получение свойств осуществляется так:

Config::Get('имя_свойста');

Сам класс:

final class Config
{
private $host = 'mysite.ru';
private $db_host = 'localhost';
private $db_name = 'mydb';
private $db_user = 'myuser';
private $db_password = 'secret';
// etc

private function __construct()
{
// чтобы нельзя было инстанцировать класс
}

public function Get( $param )
{
try {
$ref = new ReflectionProperty( __CLASS__ , $param );
}
catch( ReflectionException $e )
{
return null;
}

return $ref->getValue();
}

}


Спасибо.

По-моему кривее некуда.
Исходя из ваших потребностей, все св-ва класса лучше было засунуть в 1 private static св-во типа array.
Антон Макаренко:
Да, parse_ini_file() очень удобно!
Можно элегантно объединить способ с ini-файлом и константами:

// parse config
$CFG=parse_ini_file(array_shift(glob(dirname(__FILE__).'/*'.$_SERVER['HTTP_HOST'].'.ini')));
// automatic config values
// ...
//
// define all config values
foreach ($CFG as $k=>$v)
define('CFG_'.$k, $v);
unset($CFG);

Если "прыгать" с хоста на хост, то просто создаем ini-файл "[что-нибудь]<имя хоста>.ini"
Например, сайт на хосте "host.com": создаем файл "www.host.com.ini" и парсинг обеспечен, если обращаться как host.com и как www.host.com
kernel32:
Извините, а никто случайно не знает, сколько времени "кушает" parse_ini_file() ? А то среди моих товарищей ходили слухи, что она тормознута немного.
P.S. Сам я ее скорость не проверял
Антон Макаренко:
Попробовал замерить:
878 байт ini файл
2160 замеров (с перерывом в секунду)
0.392049537037 мс (треть милисекунды) среднее время парсинга

Имхо, парсинг не должен превышать по времени preg_replace() "средней жирности"
kernel32:
Имхо, парсинг не должен превышать по времени preg_replace() "средней жирности"
То есть это вполне нормально? Ну, для файлов в среднем размере 1Кбайт :)
Антон Макаренко:
Заметил, что php почему-то добавляет точку в конце $_SERVER['HTTP_HOST'], если обратиться по URL типа http://forum.dklab.ru./
Поэтому можно заменить строку парсинга ini-файла на
$CFG=parse_ini_file(array_shift(glob(CFG_CORE_ABS.'/*'.preg_replace('/[^a-z0-9]+$/i', '', $_SERVER['HTTP_HOST']).'*.ini')));
Хотя, конечно же, лучше делать редирект на правильный URL на уровне Apache
Дмитрий Котеров:
php почему-то добавляет точку
Это не PHP, это стандарт CGI такой: в HTTP_HOST попадает значение, переданное в заголовке Host, без всяких изменений. А его таким шлет браузер. Там еще и порт может быть, между прочим (даже если написать :80, кажется).

Эта тема на forum.dklab.ru