За последние 24 часа нас посетили 20269 программистов и 1083 робота. Сейчас ищут 683 программиста ...

Оцените класс для работы с INI файлами

Тема в разделе "Прочие вопросы по PHP", создана пользователем geone, 4 окт 2015.

  1. geone

    geone Новичок

    С нами с:
    4 окт 2015
    Сообщения:
    139
    Симпатии:
    0
    Я на форуме в первые и вообще из меня программист не очень. Так что попрошу ногами меня не бить, а лишь указать мне на ошибки (За этим я сюда пришёл). Мне этот класс нужен для управления конфигурацией, языковыми пакетами и ещё всякой ерундой, но мне кажется что он слегка кривоват.

    А вот и сам класс ini.class.php:

    Код (PHP):
    1. <?php
    2. // Класс для работы с .INI файлами
    3. class INI {
    4.     
    5.     // Парсит файл и возвращает массив
    6.     public static function parse($path){
    7.         if(!file_exists($path)) {
    8.             throw new Exception('INI файл: ' . $path . ', не существует!');
    9.         }
    10.         
    11.         return parse_ini_file($path);
    12.     }
    13.     
    14.     // Получает значение элемента по ключу
    15.     public static function get($path, $key) {
    16.         $array = INI::parse($path);
    17.         
    18.         if(!isset($array[$key])){
    19.             $array[$key] = $key;
    20.             file_put_contents($path, "\n$key = \"$key\"", FILE_APPEND);
    21.         }
    22.         
    23.         return $array[$key];
    24.     }
    25.     
    26.     // Обновляет значение элемента по ключу
    27.     public static function upgrade($path, $key, $value) {
    28.         if(!file_exists($path)) {
    29.             throw new Exception('INI файл: ' . $path . ', не существует!');
    30.         }
    31.         
    32.         $array = INI::parse($path);
    33.         $array[$key] = $value;
    34.         
    35.         $current = "";
    36.         foreach ($array as $key => $value) {
    37.             $current .= "\n$key = \"$value\"";
    38.         }
    39.         
    40.         file_put_contents($path, $current);
    41.     }
    42.     
    43.     // Удаляет элемент
    44.     public static function remove($path, $key) {
    45.         if(!file_exists($path)) {
    46.             throw new Exception('INI файл: ' . $path . ', не существует!');
    47.         }
    48.         
    49.         $array = INI::parse($path);
    50.         unset($array[$key]);
    51.         
    52.         $current = "";
    53.         foreach ($array as $key => $value) {
    54.             $current .= "\n$key = \"$value\"";
    55.         }
    56.         
    57.         file_put_contents($path, $current);
    58.     }
    59. }
    Добавлено спустя 25 минут 58 секунд:
    Ребят пожалуйста не проходите мимо. Я думаю оставить комментарий не кого не затруднит
     
  2. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    пример применения забыл
     
  3. geone

    geone Новичок

    С нами с:
    4 окт 2015
    Сообщения:
    139
    Симпатии:
    0
    Да тут применять нечего

    Некий config.ini:
    Код (Text):
    1.  
    2. param1 = "value1"
    3. param2 = "value2"
    4. param3 = "value3"
    Наш PHP:
    Код (PHP):
    1. // Подключаем класс
    2. include("ini.class.php");
    3.  
    4. // Выводим значение param2
    5. echo INI::get("config.ini", "param2");
    6.  
    7. // Изменяем значение param1
    8. INI::upgrade("config.ini", "param1", "NEWvalue");
    9.  
    10. // Удаляем param3
    11. INI::remove("config.ini", "param3");
    Я это собираюсь использовать в основном в шаблонизаторе для локализации.
     
  4. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    для локализации? gettext уже придумали.
    с именованием методов каша полная. гет гетом но для записи почему-то вдруг апгрейд. а почему тогда для гета не выбрано имя типа фэтч или рид? или популейт даже. апгрейд тоже для установки значения не особо. сэт же. не?

    файл постоянно дергается. то есть в приведенном "примере" он будет загружен и распашрен три раза. а чо его в памяти-то не оставить?

    если два процесса захотят сделать апргрейд или ремув то кто победит? где защита от состояния гонки?
    на поиск файла ты исключение кидаешь а на работу с ним - нет. а если синтаксис содержимого - инвалидный? а если не удалось прочитать (ну правов не хватило например или ТЫ ЧИТАЕШЬ ДИРЕКТОРИЮ)? а если не удалось записать? а если ты пишешь в ДИРЕКТОРИЮ?

    в общем так себе работа. сотри.
     
  5. geone

    geone Новичок

    С нами с:
    4 окт 2015
    Сообщения:
    139
    Симпатии:
    0
    Мне с INI удобней работать, и создание языковых пакетов гораздо проще выходит. Да и с конфигом можно поработать.

    Я в английском не силён. Имена как нибудь подправлю.

    Я не использую этот класс как в примере.
    Класс INI подгружается ядром при вызове. А этот класс вызывается другими классами, а в них уже есть некая система кеширования.

    Я лучше всё переделаю.
     
  6. Ganzal

    Ganzal Суперстар
    Команда форума Модератор

    С нами с:
    15 мар 2007
    Сообщения:
    9.902
    Симпатии:
    969
    в смысле с конфигом? инифайлы для пхп-сайта? в массиве храни. он кэшируется зендом.

    глупость какая. если у тебя этот класс на низком уровне при чтении ключа всегда читает, при записи и удалении всегда читает и записывает - то ты на уровне выше не реализуешь кэширование. ну или у тебя эти высокоуровневые утилиты сами записывают в файл данные хранящиеся в кэше? тогда зачем этот класс нужен?
     
  7. geone

    geone Новичок

    С нами с:
    4 окт 2015
    Сообщения:
    139
    Симпатии:
    0
    Я хочу что то своё.

    Нет из них идёт обращение к классу, только когда нужно. С кешем немного сглупил, надо будет в INI классе парсинг убить.

    Для укорачивания кода. Типо набора функций.

    Добавлено спустя 24 минуты 39 секунд:
    Я даже не представляю как это реализовать. Можешь подсказать?

    То есть надо добавить проверок? А это не скажется на скорости.
     
  8. TheMrViper

    TheMrViper Новичок

    С нами с:
    5 окт 2015
    Сообщения:
    10
    Симпатии:
    0
    Не прохожу мимо, даже зарегался для этого)

    По коду есть замечания, кто вас научил при каждом Get, открывать файл и парсить его? Это очень плохой пример.
    Парсить файл нужно однократно, а не по каждому чиху.

    Рекомендаця 1:
    В начале своих скриптов делайте:
    Код (PHP):
    1. <?php
    2. INI::Load("config1.ini");
    3. INI::Load("config2.ini");
    4. ?>
    В конце делайте:
    Код (PHP):
    1. <?php
    2. INI::Save();
    3. ?>
    Использование:
    Код (PHP):
    1. <?php
    2. $val = INI::Get("config1.ini", "key");
    3. ?>
    Сам класс реализуйте так:
    Метод INI::Load(ini_name) - загружает файл и парсит его, забивая в массив данные, и сам же запихает полученый массив в общий массив файлов, ключ у него ini_name, данные как вы поняли полученные из файла. Тем самым вы сможете использовать несколько файлов, не загружая их на каждый чих и пых.
    Метод INI::Get(ini_name, key) - Очень прост, проверяет есть ли загружен ini_name, нет - выбрасывает исключение, есть - по ключу выдаёт значение из нужного массива.
    Метод INI::Save() - Проходит по всем загруженным ini файлам, и сохраняет из обратно, за один раз.
    В добавок:
    Можно еще сделать методы Set и Make, что бы на лету создавать ini файлы.
    Метод INI::Make(ini_name) - Просто создает во внутреннем массиве новый с ключем ini_name, и потом уже по этому имени можно делать INI::Set(ini_name, key, value), ну и в конце скрипта INI::Save()


    Рекомендация 2:
    И если честно INI файл для локализации так себе, практичней соорудить что то такое:
    Код (PHP):
    1. <?php
    2. $LOCALISATION = array(
    3.     'ru' => array(
    4.         'test' => 'Тест'
    5.     ),
    6.     'en' => array(
    7.         'test' => 'Test'
    8.     )
    9. );
    10. //Ну и для удобного извлечения 
    11. function Get($loc, $key) {
    12.     return $LOCALISATION[$loc][$key];
    13. }
    14. ?>
    Добавлено спустя 7 минут 31 секунду:
    Что то аж в голос посмеялся) А то что вы дергаете файл на каждый Get-Set по вашему на скорость не влияет?

    Добавлено спустя 9 минут 18 секунд:
    Дополнение к рекомендации 2:
    Если же переживаете за скорость, то можно реализовать класс LoadLoc и метод Init (или Load как хотите так и назовите), который нужно вызывать в начале скрипта, с именем локализации (ru,en), и потом из него же LoadLoc::Get(key) выдавать из загруженной локализации значения по ключу, получится что у вас всегда будет загружена нужная локализация и ничего больше. В итоге вам нужно создать по одному php файлу на каждую локализацию, и один для загрузки нужной локализации.

    От себя в добавок:
    Возможно меня побьют, но php устарел, и лучше использовать что то более новое, например: Golang, с ним за скорость можно не переживать.

    PHP, JavaScript, SQL и другой код пишите внутри тегов
    Код ( (Unknown Language)):
    1. [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
     
  9. geone

    geone Новичок

    С нами с:
    4 окт 2015
    Сообщения:
    139
    Симпатии:
    0
    Я долго боролся с локализацией, для более простой разработки шаблона. Приведённый пример не очень, много прописывать кода надо. У меня происходит так:
    Я вызываю функцию в шаблоне _e($key) выводит, _r($key) возвращает.
    если в ini нету значения с ключом оно создаётся, то есть не надо допиливать всё время файл или массив. А только в конце создания шаблона зашёл отредактировал перевод и всё.

    Кусок моего шаблона:
    Код (PHP):
    1. <div class="container">
    2.     <?php _e('Какой то текст'); ?>
    3. </div>
    4. <?php $this->foot() ?>
    Кусок php:
    Код (PHP):
    1. // Алиасы Langage::get();
    2. function _r($string) { 
    3.     return Langage::get($string); 
    4. } 
    5. function _e($string) { 
    6.     echo Langage::get($string); 
    7. }
    8.  

    Насчёт INI класса сделаю как вы сказали. Только INI::Set(ini_name, array(key => value)) так меньше кода получается.

    PHP, JavaScript, SQL и другой код пишите внутри тегов
    Код ( (Unknown Language)):
    1. [b]php][/b]Тут код[b][/[/b][b]code][/b][/color]
     
  10. geone

    geone Новичок

    С нами с:
    4 окт 2015
    Сообщения:
    139
    Симпатии:
    0
    Зацените ini.class.php V2
    Код (PHP):
    1. <?php
    2. // Класс для работы с .INI файломи, на них строиться конфигурация
    3. class INI {
    4.     private static $cache = array();
    5.     
    6.     // Парсит файл и возвращает масив
    7.     public static function Load($path) {
    8.         if(!file_exists($path)) {
    9.             static::$cache[$path] = array();
    10.         } else {
    11.             static::$cache[$path] = parse_ini_file($path);
    12.         }
    13.     }
    14.     
    15.     // Получает значение элемента по ключу
    16.     public static function Get($path, $key) {
    17.         if(!isset(static::$cache[$path])) {
    18.             static::Load($path);
    19.         }
    20.         
    21.         $array = static::$cache[$path];
    22.         
    23.         if(!isset($array[$key])) return false;
    24.         return $array[$key];
    25.     }
    26.     
    27.     // Редактирование элемента
    28.     public static function Set($path, $new = array()) {
    29.         if(!isset(static::$cache[$path])) {
    30.             static::Load($path);
    31.         }
    32.         
    33.         $array = static::$cache[$path];
    34.         foreach ($new as $key => $value) {
    35.             $array[$key] = $value;
    36.         }
    37.             
    38.         static::$cache[$path] = $array;
    39.     }
    40.     
    41.     // Удаляет элемент
    42.     public static function Remove($path, $array) {
    43.         if(!isset(static::$cache[$path])) {
    44.             static::Load($path);
    45.         }
    46.         
    47.         foreach ($array as $key) {
    48.             unset(static::$cache[$path][$key]);
    49.         }
    50.     }
    51.     
    52.     // Очищает файл
    53.     public static function Clear($path) {
    54.         if(isset(static::$cache[$path])) {
    55.             static::$cache[$path] = array();
    56.             return true;
    57.         } else {
    58.             return false;
    59.         }
    60.     }
    61.     
    62.     // Сохраняет все изменения
    63.     public static function Save() {
    64.         foreach (static::$cache as $path => $content) {
    65.             $current = "";
    66.             foreach ($content as $key => $value) {
    67.                 $current .= "\n$key = \"$value\"";
    68.             }
    69.             
    70.             file_put_contents($path, $current);
    71.         }
    72.     }
    73. }
    Описание функций:
    • INI::Load("Путь к файлу") - Подгружает файл в кэш, если нету файла создаёт его. Использовать её стоит в начале, ей можно вообще не пользоваться, она автоматически вызывается.[/*:m]
    • INI::Get("Путь к файлу", "Ключ") - Возвращает значение по ключу.[/*:m]
    • INI::Set("Путь к файлу", array("Ключ1" => "Значение1", "Ключ2" => "Значение2")) - Добавляет новые значения или изменяет.[/*:m]
    • INI::Remove("Путь к файлу", array("Ключ1", "Ключ2") - Удаляет значения.[/*:m]
    • INI::Clear("Путь к файлу") - Полностью очищает файл, не знаю где это может пригодиться, просто решил написать.[/*:m]
    • INI::Save() - Сохраняет изменения. Эту функцию следует вызывать в самом низу.[/*:m][/list:u]

      Пример:
      Код (PHP):
      1. include('ini.class.php');
      2. $file = 'file.ini';
      3. INI::Set($file, array(
      4.     'param1' => 'value1',
      5.     'param2' => 'value2',
      6.     'param3' => 'value3'
      7. ));
      8. INI::Save(); 
      Код выше создаёт файл file.ini, с содержанием:

      Код (Text):
      1. param1 = "value1"
      2. param2 = "value2"
      3. param3 = "value3"
      Осталось добавить несколько проверок от дурака)))
     
  11. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.548
    Симпатии:
    1.754
    Всё делается гораздо проще - делается не статический, а нормальный класс, чтоб экземпляры создавать, и в экземпляре ваш файл держать. И писать удобно.
    Код (Text):
    1.  
    2. $conf = new INI("filename.ini");
    3.  
    4. $param1 = $conf->get("param1");
    5. // Или даже через магию php
    6. $param2 = $conf->param2;
    7. // Или через реализацию ArrayAccess
    8. $param3 = $conf["param3"];
    9.  
    10. $conf->set("param4", "value");
    11. $conf->param5 = "value";
    12. $conf["param6"] = "value";
    А эти статические классы меня всегда так раздражают. Какое они преимущество дают?
     
  12. mahmuzar

    mahmuzar Старожил

    С нами с:
    6 апр 2012
    Сообщения:
    4.632
    Симпатии:
    425
    Адрес:
    РД, г. Махачкала.
    geone
    Состояние гонки возникает, когда два потока доступа к общей переменной в то же время. Оба потока считывают одно и тоже значение переменной. Оба потока производят какие-либо действия со значением и далее возникает гонка за то, кто последним сможет записать новое значение. Поток, который запишет значение последним перезапишет значение, которое записал предыдущий поток.
    Так же и с файлами.
     
  13. TheMrViper

    TheMrViper Новичок

    С нами с:
    5 окт 2015
    Сообщения:
    10
    Симпатии:
    0
    Вдумайтесь в само задание, никто не даёт пользователям права писать что то, потоки могу только читать, запись нужна лишь для отладки.

    Добавлено спустя 1 минуту 41 секунду:
    В данный момент лучше использовать статику, во первых - статика производительней, во вторых - в данном случае не нужно писать никому ненужный singleton

    Добавлено спустя 34 секунды:


    • Вот, это уже другое дело.
     
  14. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    повторюсь:
    1. ловить эксепшены лучше в функциях, нафик их кидать вообще в данном случае - мне не понятно.
    2. лучше вообще не писать ини файл =) а делать это руками, когда надо. Если что-то часто меняется - есть бд.
     
  15. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.548
    Симпатии:
    1.754
    Причём здесь синглтон, если файлов конфигурации много, и они грузятся в память? Один файл - один экземпляр класса. По поводу производительности - не верю, что это настолько критически заметно. Если производительнее, пишите обычные функции, без классов.
     
  16. TheMrViper

    TheMrViper Новичок

    С нами с:
    5 окт 2015
    Сообщения:
    10
    Симпатии:
    0
    Вы понимаете что он грузит только нужные файлы, статика это те же функции, просто вгруппе.

    Добавлено спустя 1 минуту 18 секунд:
    Вы издеваетесь? хранить локализацию в бд??? Это новый уровень извращения.
     
  17. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    наxyй пошел =) хами матушке своей на кухне
    аргументируй или не пацан
     
  18. mkramer

    mkramer Суперстар
    Команда форума Модератор

    С нами с:
    20 июн 2012
    Сообщения:
    8.548
    Симпатии:
    1.754
    А мой вариант с конструктором будто бы будет по всему диску искать... Ладно, если вам нравится писать
    Код (Text):
    1.  
    2. INI::get("path_to_ini_file", "param");
    вместо
    Код (Text):
    1.  
    2. $conf->param
    пишите
     
  19. TheMrViper

    TheMrViper Новичок

    С нами с:
    5 окт 2015
    Сообщения:
    10
    Симпатии:
    0
    Не по всему диску искать, но гонять переменную по функциям нет смысла, можно использовать статику.
     
  20. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    аргументов не будет, значит? Истерика была, а аргументов нет и не будет видимо. =)
     
  21. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    С таким подходом вам и голанг не поможет ) Го не серебренная пуля, там точно так же можно написать тормозящее, жрущее память приложение.
     
  22. TheMrViper

    TheMrViper Новичок

    С нами с:
    5 окт 2015
    Сообщения:
    10
    Симпатии:
    0
    Если говорить про Го, то это уже другое дело, и архитектура там другая.
    Я никогда не понимал, зачем городить миллион классов на миг.
    php - Это как бабочка, которая живет всего день, но строит себе дом, и после постройки сразу умирает.
     
  23. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.410
    Симпатии:
    1.768
    миллион классов городят в пхп не потому, что это круто. Причина куда смешнее. Найти хорошего пхпшника сложно. А найти какого-нить джависта - проще. Джависта пересаживают на пхп, он тащит свой привычный уклад с собой.
     
  24. TheMrViper

    TheMrViper Новичок

    С нами с:
    5 окт 2015
    Сообщения:
    10
    Симпатии:
    0
    Я про всевозможные фреймворки, их везде используют, для псевдо облегчения работы, но в итоге уменьшают скорость приложения
     
  25. romach

    romach Старожил

    С нами с:
    26 окт 2013
    Сообщения:
    2.904
    Симпатии:
    719
    Очень просто. Покажите мне на го:
    1. Вменяемую систему управления зависимостями, не так что бы всё скачалось в src/, а с версиями, под каждый проект и без костылей.
    2. Нормальный фреймворк с абстракцией над базами данные, кэшированием, файловой системой (в т.ч. облачной)
    3. Реализации OAuth для всех популярных и не очень провайдеров, работе с различными типами файлов, очередями и прочими необходимыми вещами.
    При этом все должно быть с вменяемой документацией, code style и сообществом. Я уж молчу, раз мы говорим о вебе, хотя бы одну CMS с нормальным функционалом. Этого нет на Го и даже на ноде, в отличии от PHP.

    К чему всё это? К тому что прежде всего важна скорость и удобство разработки, а не экономия на спичках и красивых графиках, отсюда и миллион классов с абстракциями и интерфейсами на один миг )

    p.s. го крут, как и нода. Просто нужно понимать в чем и применять инструмент по необходимости.