Предисловие
Приветствую Вас хабравчане.
В течении нескольких лет разработки и поиска оптимальных решений для решения задач с использованием PHP перепробовал разные способы хранения и организации доступа к настройкам сайта. Одним из последних (и основных) способов хочу поделиться с Вами. Если похожие посты уже были — извиняюсь, не нашёл.
Требования и условия задачи
- Удобство хранения и доступа
- Высокая скорость работы
- Глобальная область видимости
- Относительно короткая запись
- Хранение двух видов настроек: не изменяемых и переменных
- PHP >= 5.3
Структура каталогов (+ файлов) сайта (для теста)
|-[classes]
| |-config.php
|-config.json
|-index.php
«Желаемый» способ доступа к настройкам
Исходный массив data:
$data = array( 'paramName_1' => array('paramName_2' => array('paramName_N' => 'value') ) );
Доступ к настройкам config.json:
// Прямой доступ к массиву:
$value = cfg()->data['paramName_1']['paramName_2']['paramName_N'];
// Доступ "как к объекту"
$value = cfg()->paramName_1->paramName_2->paramName_N();
// и
$value = cfg()->paramName_1->paramName_2('paramName_N');
Доступ к «глобальным изменяемым» настройкам:
// получить значение:
$value = cfg()->varParam;
// Запись значения:
cfg()->varParam = 'value';
// и
cfg()->varParam('value')->varParam_2(1234)->varParam_N(TRUE);
JSON. Основной файл настроек (примерно)
config.json
{
"site_name" : "SiteName",
"site_slogan" : "слоган моего сайта",
"http" : "http://",
"domen" : "mysite.ru",
"local_domen" : "mysite.local",
"site_templates_name" : "def",
"icon_name" : "icon.ico",
"style_title_separator" : ":",
"style_compress" : true,
"www_compress" : true,
"index_separator" : "{{separator}}",
"robots" : ["User-agent: *", "Allow: /", "Disallow: /search"],
"date" : { "GMT" : "D, d M Y H:i:s" },
"db" : {
"type" : "mysqli",
"config":{
"local" : {
"dbName1" : {"host" : "127.0.0.1" , "user" : "root" , "pass":"" , "prefix" : "f45636g_" , "name" : "dbName1"}
},
"global":{
"dbName1" : {"host" : "" , "user" : "" , "pass":"" , "prefix" : "f45636g_" , "name" : "dbName1"}
}
}
},
"session" : {
"name" : "sid",
"prefix" : "rgbetnm7_",
"cookie_token_name" : "token",
"life_time": 0,
"db_life_time": 60,
"token_key" : "nvgo275o2572067n20937hrstyrty3no49",
"sess_token_name" : "x2kc85mv39cm29375nv69834noifjirhg"
}
}
Содержимое INDEX.PHP
spl_autoload_extensions('.php');
spl_autoload_register();
define('DIRSEP', DIRECTORY_SEPARATOR);
define('DIR', __DIR__);
function cfg(){
RETURN classes\Config::obj();
}
/* остальной код */
Содержимое classes\CONFIG.PHP
classes\Config.php
class Config{
//------------------------------ GLOBAL APP CONFIG ------------------------------//
public $status = 200; // Default "200 OK"; Type (int)
public $page_type = NULL; // глобальный параметр
public $mode = NULL; // глобальный параметр
//------------------------------ OBJECT & CONFIG.JSON ------------------------------//
private $_data; // хранит в виде массива config.json
private static $once = NULL; // хранит объект класса Config
private static $file = 'config.json'; // имя файла
private $get_arr = NULL; // индексный массив с именами ключей
static function obj(){
if(is_null(self::$once)):
self::$once = new self();
$file = DIR . DIRSEP .self::$file;
$json = is_file($file) ? file_get_contents($file) : NULL;
self::$once->_data = json_decode($json, TRUE);
endif;
RETURN self::$once;
}
public function __get($name) {
if($name === 'data') RETURN $this->_data;
$this->get_arr[] = $name;
RETURN self::obj();
}
public function __call($name, $arg) {
if(count($arg) > 1) RETURN NULL;
if( property_exists($this, $name) ){
if(count($arg) !== 1) RETURN NULL;
$this->$name = $arg[0];
RETURN self::obj();
}else{
$this->get_arr[] = $name;
$result = $this->_data;
foreach ($this->get_arr as $name):
if( !is_array($result) ) RETURN NULL;
$result = $result[$name];
endforeach;
$this->get_arr = NULL;
RETURN isset($arg[0]) && is_array($result) ? $result[$arg[0]] : $result;
}
}
public function __destruct() { $this->_data = NULL; }
}
ТЕСТИРУЕМ
Ниже приведённый способ доступа будет работать глобально, в любой части года.
// получаем префикс для локальной базы
$dbPrefix = cfg()->db->config->local->dbName1->prefix();
// или
$db_name = "dbName1";
$dbPrefix = cfg()->db->config->local->$db_name->prefix();
// или
$dbPrefix = cfg()->db->config->local->$db_name('prefix');
// или
$dbPrefix = cfg()->data['db']['config']['local'][$db_name]['prefix']; // Плохой способ: необходимо указывать имя массива + избыток скобок и кавычек
// получаем robots с индексом 2
$robots_item = cfg()->robots(2); // вернёт значение "Disallow: /search"
// получаем значение глобальной переменной
$status = cfg()->status;
// устанавливаем значения сразу нескольких глобальных переменных
cfg()->status(404)->mode('www')->page_type('main');
Вывод
В результате получается достаточно компактный, понятный и читаемый код.