PHP-класс для работы с INI-файлами

    Класс-помощник для работы с INI-файлами. Класс реализует шаблон проектирования "Строитель". В представленном классе идет реализация функционала для работы с INI-файлами. В качестве базового функционала представлено создание, добавление и чтение секций, добавление и удаление ключей и другой функционал.


    Первым делом необходимо объявить переменные, которые отвечают за структуру файла, путь к файлу и тип сканирования:

    /**
     * @var array Структура ini файла
    */
    private array $structure = [];
    /**
     * @var int Тип сканирования
    */
    private int $scannerMode;
    /**
     * @var string Путь к файлу
    */
    private string $path;

    В конструкторе метода укажем путь к файлу (для создания) и тип сканирования, а также вызовем метод получения структуры файла:

    public function __construct(string $path, int $scannerMode = INI_SCANNER_TYPED) {
    	$this->path = $path;
    	file_put_contents($path, null, LOCK_EX);
    	$this->scannerMode = $scannerMode;
    
    	$this->setInitStructure();
    }

    Метод получения структуры файла выглядит следующим образом:

    private function setInitStructure(): void {
    	$this->structure = parse_ini_file($this->path, true, $this->scannerMode);
    }

    Метод parse_ini_file получает в качестве аргументов путь к файлу, флаг получения многомерного массива и типа сканирования. Мы ставим по умолчанию флаг многомерного массива как true, так как нам проще работать с такими массивами. Тип сканирования может быть:

    • INI_SCANNER_NORMAL (по умолчанию в PHP)

    • INI_SCANNER_RAW

    При INI_SCANNER_RAW значения опций (ключ => значение) не будут обрабатываться. Также с версии PHP 5.6.1 завезли тип INI_SCANNER_TYPED. В этом режиме типы boolean, null и integer будут, по возможности, сохраняться. Строковые значения "true""on" и "yes" будут преобразованы в TRUE"false""off""no" и "none" в FALSE"null" преобразуется в NULL. Кроме этого, все числовые строки будут, по возможности, преобразованы к целым числам. Вроде как это лучше, чем остальные варианты, по этому используем его.

    Вспомогательные методы

    Напишем публичный метод получения всей структуры файла:

    public function getStructure(): array {
    	return $this->structure;
    }

    Чаще всего необходимо получать какое-то значение или всю секцию файла. Давайте напишем простые методы получения этих значений:

    public function getSection(string $section): array {
    	return $this->structure[$section];
    }
    
    public function getValue(string $section, string $key) {
    	return $this->getSection($section)[$key];
    }

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

    public function addSection(string $section): Ini {
    	if (array_key_exists($section, $this->structure)) {
    		throw new Exception("Секция {$section} уже существует");
    	}
    
    	$this->structure[$section] = [];
    
    	return $this;
    }

    В данном случае выбрасывается простой exception, хотя лучше всего было бы использовать собственные исключения.

    Теперь сделаем метод, который добавлял бы значения в определенные секцию:

    public function addValues(string $section, array $values): Ini {
    	$this->structure[$section] = array_merge($values, $this->structure[$section]);
    
    	return $this;
    }

    Но не всегда надо добавлять значения, иногда нужно из переназначать. Напишем такой метод:

    public function setValues(string $section, array $values): Ini {
      foreach ($values as $key => $value) {
      	$this->structure[$section][$key] = $value;
      }
    
      return $this;
    }

    С добавлением, назначением и чтением мы разобрались, теперь сделаем возможность удаления секции и ключей в секциях:

    public function removeSection(string $section): Ini {
      unset($this->structure[$section]);
    
      return $this;
    }
    
    public function removeKeys(string $section, array $keys): Ini {
      foreach ($keys as $key) {
      	unset($this->structure[$section][$key]);
      }
    
      return $this;
    }

    Обратите внимание, что методы добавления и удаления реализуют шаблон проектирования "Строитель".

    Осталось дело за малым - написать метод записи в файл:

    public function write(): void {
      $iniContent = null;
    
      foreach ($this->structure as $section => $data) {
      	$iniContent .= "[{$section}]\n";
    
      foreach ($data as $key => $value) {
      	$iniContent .= "{$key}={$value}\n";
      }
    
      $iniContent .= "\n";
      }
    
    	file_put_contents($this->path, $iniContent, LOCK_EX);
      $this->setInitStructure();
    }

    Надеюсь, что вам будет полезен данный помощник по работе с INI файлами в PHP. Если есть предложения по улучшению, то буду рад их выслушать.

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 18

      +3
      Главный вопрос, почему не оформили в виде composer пакета? Как предлагается этим пользоваться?
        –1
        Вы можете скачать код этот и внедрить к себе в проект. Как минимум — это ознакомительная часть, может кому понадобиться для реализации своих идей. Можно было оформить в качестве пакета, но позже сделаю это.
          +5
          Это так не работает. Никто не будет «качать и внедрять». Чтобы пользоваться, нужен composer пакет. Нужны тесты. Это прям минимум.

          позже сделаю это.


          почти всегда можно читать как «никогда». Сам это проходил)
            0
            Откуда скачать-то, даже если желающий найдется? Ссылок на гитхаб не наблюдаю.

            Ну и да — прежде чем писать свой велосипед, неплохо бы сделать хотя бы наколеночный обзор существующих решений (неужели в мире никому не нужно было работать с ini на php, учитывая, кхм, то, что php.ini — это INI файл?)
              +1

              но php же не на php написан

          0

          del

            0
            Что имеете ввиду?
            0
            Кажется проще использовать github.com/yosymfony/toml
              +1
              var $ini = new Ini('app.ini');
              $ini->addSection('hello');
              $ini->addSection('Hello'); // опа
              $ini->addSection('hello]there'); // поломалось
              $ini->addValues('hello', ['an=y'=>'va\nlue;']); // приветик
              
                –1
                Вы не соблюдаете синтаксис работы с ini файлами. Написать проверку на ключи можно, а на значения нет смысла. В значение может быть и строка и цифра и символы. Этот момент был оставлен на отмашку пользователя класса.
                  0
                  Если бы я хотел заморачиваться с соблюдением синтаксиса ini-файла, мне не нужен для этого класс. Это Вы не проверяете входные данные, хотя бы элементарно. Вы хотите сделать «удобно», но самую рутину «оставляете на отмашку пользователю класса».

                  В догонку: в ini-файле могут быть записи без секции.
                    0
                    вроде секция все равно будет [DEFAULT]
                    +3
                    Мне кажется, хорошие классы-хэлперы должны под капотом решать максимально возможное количество проблем, включая обработку ошибок и вопросы безопасности. Просто когда такие моменты оставлены на отмашку пользователя, это всё равно, что написать оболочку для mysqli, которая очень удобная в использовании, но под капотом заменяет в SQL-запросах знаки вопроса на значения соответстующих переменных — просто вставляя их как есть в запрос. Типа, моменты с экранированием значение переменных оставлены на отмашку пользователям класса.

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

                    Единственное, что мне в вашем коде нравится — это то, что вы открывающие фигурные скобки на той же строке пишете. А сама статья… я вам практически гарантирую, что впечатления от фидбэка у вас будут негативные, потому что формат статьи такой. Она практически из одного кода состоит. Его будут критиковать и тыкать вас в ошибки, причём если вы учтёте все замечания и обновите статью, критиковать вас продолжат, потому что обновление никто читать не будет — достаточно того, что в комментариях цитируется ваш старый, который вы уже поправили, код. Люди будут смотреть на эти старые цитаты и будут критиковать именно их.
                      0
                      Единственное, что мне в вашем коде нравится — это то, что вы открывающие фигурные скобки на той же строке пишете


                      Что, если правильно помню, противоречит PSR-2, к сожалению.
                        0
                        И спецификации PSR-12, которая пришла на смену PSR-2, это тоже противоречит, кстати. И повлиять на спецификацию вы никак не сможете, даже если вы в одиночку написали кода на PHP больше, чем было в тех исходниках, которые они брали на анализ для составления стандартов.
                  0

                  Лучше место ini использовать yaml.

                    0
                    Почему и чем?
                    0

                    Оформить пакет композера не сложно. Я делал это год назад и как то справился. Кажется надо просто в репозитории иметь composer.json где будут прописаны пути к классам.
                    Как пример https://packagist.org/packages/sbwerewolf/language-specific. И потом в жизни самому так удобней использовать. Ни какого копипаста. Подключил зависимостьти оно само работает. И само обновиться когда что то в исходниках поправишь.
                    По коду мелкое замечание. Не красиво использовать '\n' красиво это PHP_EOL.
                    И верное замечание про проверки. Если хочешь что бы таоим кодом пользовались, то сделвй его удобным.
                    Можно сделать фабрику что бы пользоаатель библиотеки мог подсунуть свою реализацию, но в своей реализации сделать проверки. Кому будет мало сможет твой класс пепеписать и подставить.
                    В порядке друкжеской критики.
                    Спасибо что поделился кодом.

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

                    Самое читаемое