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

Хранение и работа с настройками JSON + PHP ООП

Предисловие


Приветствую Вас хабравчане.
В течении нескольких лет разработки и поиска оптимальных решений для решения задач с использованием 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');

Вывод


В результате получается достаточно компактный, понятный и читаемый код.

Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.