Singleton и конфиги

Тема в разделе "PHP Pro", создана пользователем Den1xxx, 17 янв 2017.

XEvil 4.0 Релиз Состоялся!
  1. Den1xxx

    Den1xxx

    Moderator
    Регистр.:
    15 янв 2014
    Сообщения:
    282
    Симпатии:
    158
    Добрый день.
    Хочу поговорить об оптимизации загрузки конфигов.

    В движке часто используются конфиги, как правило, в виде сериализованных файлов.
    Количество — 50+
    Многие загружаются редко, другие каждый раз, а некоторые несколько раз за сессию.
    Чтобы не читать файл несколько раз подряд в течение сессии, решил спроектировать загрузку конфигов по шаблону «синглтон».

    Пример:
    PHP:
    class fn_store_config  {
        public 
    $file_config 'fnstoreconf.ini';
        public 
    $default_config =
            array(
                
    'title'=>'Stores',
                
    'store'=>'1',
                
    'prefix'=>'store_',
                
    'perpage'=>100,
            );   
        public 
    $config;
        static private 
    $instance;

        public static function 
    getInstance() {       
            if(empty(
    self::$instance)) {
                
    self::$instance = new self;
            }
            return 
    self::$instance;
        }   

        public static function 
    get_config() {       
            if(empty(
    self::$instance)) {
                
    self::$instance = new self;
            }
            return 
    self::$instance->config;
        }   
           
        private function 
    __construct() {
            if (
    is_file(CONFIG_PATH.$this->file_config)) {
                
    $this->config unserialize(file_get_contents(CONFIG_PATH.$this->file_config));
            } else {
                
    $this->config $this->default_config;
            }
        }

        private function 
    __clone(){}
    }
    Всё работает. При вызове fn_store_config::getInstance() отдаёт объект, при вызове fn_store_config::get_config() — массив.

    Замечательно, обрадовался я. И сразу возник вопрос: как поставить создание кинфигов на поток?
    Например, задаём имя файла конфига — расширяем класс и готово.
    Попробовал создать класс, расширить — отдает значения родительского класса вместо своих.
    Как сделать подобную фабрику правильно?
     
  2. Den1xxx

    Den1xxx

    Moderator
    Регистр.:
    15 янв 2014
    Сообщения:
    282
    Симпатии:
    158
    Странно, что никто не ответил.
    Тема вроде актуальная — загрузка конфигов в память, чтобы не читать несколько раз за сессию.
    Решение было найдено, и я обошёлся без классов и модных синглтонов.
    Привожу функцию, которая будет загружать конфиг из файла, хранить и при повторной попытке загрузки отдавать из памяти.
    PHP:
    /*
    * Загружает сериализованный конфиг
    * Адрес файла использем в качестве ключа
    */
    function load_serialized_config($file) {
        
    //Переменная для постоянного хранения конфигов
        
    static $config = array();
        if (
    array_key_exists($file,$config)) {
            
    //?
        
    }    elseif (is_file(CONFIG_PATH.$file)) {
            
    $config[$file] = unserialize(file_get_contents(CONFIG_PATH.$file));
        } else {
            
    $config[$file] = array();
        }
        return (
    $config[$file]);
    }
    Уверен, кому-то ещё пригодится!
     
  3. javx

    javx

    Регистр.:
    28 авг 2015
    Сообщения:
    520
    Симпатии:
    256
    Используй мемкеш. Или опкеш (компиляция в байткод только первый раз). Конфиги меньшая из бед, всегда смотри через профайлер какой участок кода работает неоправданно большое время и рефакторь его.
     
    Den1xxx нравится это.
  4. Den1xxx

    Den1xxx

    Moderator
    Регистр.:
    15 янв 2014
    Сообщения:
    282
    Симпатии:
    158
    Спасибо за внимание к проблеме. Однако применить почти все Ваши советы не представляется возможным.
    Я разрабатываю движок, который собираюсь скоро выложить в открытый доступ.
    Т. е. он будет применяться людьми, как правило, на виртуальном хостинге.
    Там мемкеш или опкеш не всегда есть.

    Рефакторинг тоже показывает, что повторное чтение файла слегка «подтормаживает» систему (особенно если диски не SSD).
    Между тем, 54 файла занимают всего 38кб — почему бы не хранить это в памяти, чтобы не лезть на диск раз за разом?

    Тут видишь какая проблема. Static переменные в функциях применяются редко. Поэтому пользоваться ими многие самоучки, как я, не умеют. Городим велосипеды, как в Яве, хотя простое решение лежит на поверхности. А ООП ради ООП в PHP — зло. PHP не висит постоянно в памяти, поэтому функциональный подход работает быстрее и менее затратен.
     
    Последнее редактирование: 20 янв 2017
  5. javx

    javx

    Регистр.:
    28 авг 2015
    Сообщения:
    520
    Симпатии:
    256
    Den1xxx нравится это.
  6. nejtr0n

    nejtr0n Постоялец

    Регистр.:
    24 янв 2014
    Сообщения:
    124
    Симпатии:
    73
    Чтобы отдавался не родительский класс, а свой, замените self на static в конструкторе singleton.
    И почитайте про позднее статическое связывание - http://php.net/manual/ru/language.oop5.late-static-bindings.php
     
    Den1xxx нравится это.
  7. etok

    etok Создатель

    Регистр.:
    6 окт 2010
    Сообщения:
    37
    Симпатии:
    11
    Я обычно закрываю allow_url_fopen в php.ini. Тогда file_get_contents перестает работать. Предпочитаю cURL, а для чтения конфигов parse_ini_file. Так мне представляется кашернее...

    Хороший обзор. В защиту xml могу сказать, что он все еще универсальный промышленный стандарт. Json моден, но нечитаем. То ли дело ini - человеческие букавки, никакой сериализации. Хоть с телефона по SSH заходи и правь что приспичит :)
     
    Последнее редактирование: 11 фев 2017
  8. Den1xxx

    Den1xxx

    Moderator
    Регистр.:
    15 янв 2014
    Сообщения:
    282
    Симпатии:
    158
    Это только русские символы нечитаемы. Зато простой и безопасный для БД и передачи по сети.
    В своё время думал перейти на JSON. Но там были какие-то тёрки с лицензированием, ну его на...
    Вложенный конфиг на нем по-человечески не сделаешь.
    Имхо нечего юзеру конфиги впрямую на сервере читать, для этого есть админка.
    А специалисту параметр в сериализованном файле подсмотреть не проблема.

    Пока для хранения массива в строке альтернативы для сериализации нет.
    Мало того, она ещё и очень быстро работает.
     
  9. etok

    etok Создатель

    Регистр.:
    6 окт 2010
    Сообщения:
    37
    Симпатии:
    11
    Так я не юзер - я PowerUser :)

    А если серьезно, то у нас такой подход. Мы делаем админку под "тупого юзера" и вней все что нужно для оперативного управления. Конфиги же, не относятся к "оперативному". Плюс они могут радикально повлиять на систему. Поэтому к ним имеет доступ только "специально тренированный" человек - админ понимающий в *NIX-ах. Тем самым мы
    1. не тратим время на написание управляющих скриптов для админки в части конфигов
    2. не "парим" мозг простому контент-манагеру объяснениями что это за конфиги такие
    3. стимулируем образование админов-эникейщиков и делаем их более ценными в глазах работадателя (попробуй замени админа по *NIX-ам)
    Короче все счастливы. Мне так кажется. А json - это здорово. И работает в 10 раз быстрее чем связка XML - XSLT. Только каждый нож на кухне идеально заточен под что-то свое.
     
  10. Den1xxx

    Den1xxx

    Moderator
    Регистр.:
    15 янв 2014
    Сообщения:
    282
    Симпатии:
    158
    ...кроме работодателя.
    Он мог поручить кому-то на полставки, а нанял спеца на хорошую зарплату.

    У меня в движке 100500 разных доступов (доступы на модули, доступы на поля в отдельных модулях, доступ по «уровню доступа» — админом назначается юзверю любое число) — можно формировать из них наборы для ролей «директор», «модератор», «начальник склада» — как «админ» назовёт и настроит, так и будет. Однако напрямую конфиги админ не правит — есть админка, добро пожаловать, в правом уголке ещё и помощь на каждой странице. Человекам с ограниченными правами просто выключается отображение блоков админки, которыми они не могут управлять. Вебмастер же может уже в коде шаблона первоначально настроить под конкретного админа — например, при создании товара выключить заполнение полей, которыми админ всё равно пользоваться не будет. Или прописать стили под проект.

    Всё поведение шаблонов хранится в 1 месте — в папке шаблона проекта. При создании нового проекта будут настроены другие шаблоны поведения. Если настраивать вебмастеру лень (или проект имеет ограниченный бюджет), то не пишет ничего. Движок поднимет шаблоны из стандартной папки — всё будет работать «из коробки», но вёрстка примитивная и на таблицах, зато нет заморочек со стилями.
    Такая вот реализация MVC.