Пакет Zend-Config представляет простой механизм для работы с конфигурацией приложения. Он включает класс Config
, представляющий данные конфигурации и предоставляющий объектный интерфейс доступа к ним. Для начала рассмотрим несколько примеров:
<?php
use Zend\Config\Config;
$config = new Config([
'database' => [
'dbname' => 'my_db',
'user' => 'root',
'password' => 123,
],
]);
echo $config->database->user; // "root"
При инстанциации этого класса ему необходимо передать массив конфигурации в качестве первого параметра. Конструктор класса так же принимает второй, булевый параметр, который определяет, является ли конфигурация неизменяемой (read only) или нет:
<?php
use Zend\Config\Config;
$config = new Config([], true); // по умолчанию - false
$config->database = [];
$config->database->user = 'root';
$config->setReadOnly(); // Делаем конфигурацию неизменяемой
$config->database->password = 123; // Error
Получить доступ к данным конфигурации можно так же с помощью метода get
, который принимает помимо имени целевой опции, так же значение по умолчанию, которое будет возвращено в случае, если опция отсутствует:
<?php
use Zend\Config\Config;
$config = new Config([
'database' => [
'dbname' => 'my_db',
'user' => 'root',
'password' => 123,
],
]);
echo $config->database->get('host', 'localhost'); // "localhost" - так как данной опции конфигурации не задано
В том случае, если необходимо слить две конфигурации в одну, можно воспользоваться методом merge
:
<?php
use Zend\Config\Config;
$configA = new Config(['x' => 1, 'y' => 2]);
$configB = new Config(['x' => 0, 'z' => 3]);
$configA->merge($configB);
echo $configA->x; // 0
echo $configA->y; // 2
echo $configA->z; // 3
Чтение и запись конфигураций
Для чтения или записи конфигураций, используются классы из пространств имен Zend\Config\Reader
и Zend\Config\Writer
соответственно. Семантика этих классов определяется интерфейсами ReaderInterface
и WriterInterface
, а именно следующими методами:
ReaderInterface
fromString
- чтение данных конфигурации из строкиfromFile
- чтение данных конфигурации из файла
WriterInterface
toString
- запись конфигурации в строкуtoFile
- запись конфигурации в файл
Для начала рассмотрим простой пример реализации собственных классов для чтения конфигурации из PHP скрипта, содержащего массив конфигурации, а так же записи в этот файл:
<?php
use Zend\Config\Config;
use Zend\Config\Reader\ReaderInterface;
use Zend\Config\Writer\WriterInterface;
class PhpArrayReader implements ReaderInterface{
public function fromString($string){
eval('$result = ' . $string . ';'); // Не безопасно! Не делайте так, код приведен в качестве примера!
return $result;
}
public function fromFile($filename){
if(!file_exists($filename)){
return [];
}
return include($filename);
}
}
class PhpArrayWriter implements WriterInterface{
public function toString($config){
if($config instanceof Config){
$config = $config->toArray();
}
return var_export($config, true);
}
public function toFile($filename, $config, $exclusiveLock = true){
$flags = 0;
if($exclusiveLock){
$flags |= LOCK_EX;
}
file_put_contents($filename, $this->toString($config), $flags);
}
}
$reader = new PhpArrayReader;
$config = new Config($reader->fromFile('conf.php'), true);
$writer = new PhpArrayWriter;
$config->database->password = 321;
$writer->toFile('conf.php', $config);
Следует помнить, что все методы интерфейсов могут принимать как массив конфигурации, так и экземпляр класса
Config
, что требует правильной обработки. Для преобразования конфигурации в массив можно использовать методtoArray
, как показано в примере выше.
Пакет Zend-Config включает множество готовых кассов для чтения и записи конфигураций, которые вы можете использовать вместо собственной реализации:
ReaderInterface
Ini
- чтение из формата INIJson
- чтение из формата JSONXml
- чтение из формата XMLYaml
- чтение из формата YAMLJavaProperties
- чтение из формата JavaProperties
WriterInterface
PhpArray
- запись в формат массива PHPIni
- запись в формат INIJson
- запись в формат JSONXml
- запись в формат XMLYaml
- запись в формат YAML
С использованием перечисленных классов наш код из предыдущего примера будет выглядить так:
<?php
use Zend\Config\Config;
use Zend\Config\Writer\PhpArray;
$config = new Config(include('conf.php'), true);
$writer = new PhpArray;
$config->database->password = 321;
$writer->toFile('conf.php', $config);
Процессоры
Иногда конфигурация приложения нуждается в дополнительной обработке перед использованием, к примеру, для замены всех вхождений констант на их значения. Для реализации этой логики используются классы пространства имен Zend\Config\Processor
. Семантику этих классов описывает интерфейс ProcessorInterface
, включающий два метода:
processValue
- обработка и преобразование значения конфигурацииprocess
- обработка конфигурации в целом
Попробуем реализовать собственный процессор с использованием этого интерфейса:
<?php
use Zend\Config\Processor\ProcessorInterface;
use Zend\Config\Config;
use Zend\Config\Exception\InvalidArgumentException;
class UpperProcessor implements ProcessorInterface{
public function processValue($value){
return strtoupper($value);
}
public function process(Config $value){
if($value->isReadOnly()){
throw new InvalidArgumentException('Cannot process config because it is read-only');
}
foreach($value as $key => $val){
if($val instanceof Config){
$value->$key = $this->process($val);
}
else{
$value->$key = $this->processValue($val);
}
}
}
}
$config = new Config([
'foo' => 'bar',
], true);
$processor = new UpperProcessor;
$processor->process($config);
echo $config->foo; // "BAR"
В пакет Zend-Config входят следующие процессоры:
Token
- выполняет замену вхождений указанных токеновConstant
- частный случайToken
, выполняющий замену вхождений константFilter
- выполняет обработку значений конфигурации с помощьюZend\Filter
Translator
- выполняет локализацию значений конфигурации с помощьюZend\I18n
Queue
- объединяет несколько процессоров в один
<?php
use Zend\Config\Config;
use Zend\Processor\Token;
use Zend\Processor\Constant;
use Zend\Processor\Filter;
Zend\Filter\StringToUpper;
use Zend\Processor\Queue;
$config = new Config([
'token' => 'token',
'constant' => 'CONST',
], true);
$queue = new Queue;
$token = new Token;
$token->addToken('token', 'foo');
$queue->insert($token);
define('CONST', 'bar');
$constant = new Constant;
$queue->insert($constant);
$filter = new StringToUpper;
$queue->insert($constant);
$queue->process($config);
echo $config->token; // "FOO"
echo $config->constant; // "BAR"
Фабрика конфигураций
Класс Factory
предоставляет удобный интерфейс доступа к конфигурациям с помощью следущих статичных методов:
fromFile
- чтение конфигурации из файлаfromFiles
- чтение конфигурации из нескольких файловtoFile
- запись конфигурации в файл
Удобство данного класса в том, что он использует расширение файла для выбора подходящего Reader
и Writer
в каждом конкретном случае:
<?php
use Zend\Config\Factory;
$config = Factory::fromFiles(['config.php', 'config.json', 'config.xml'], true);
Factory::toFile('config.yaml', $config);
Этот пример показывает, как можно с помощью класса Factory
объединить конфигурации разных форматов (PHP, JSON, XML) в один файл (YAML).
Методы
fromFiles
иfromFile
в качестве второго параметра принимают булевое значение, определяющее в каком виде должна быть возвращена конфигурация: true - в виде экземпляра классаConfig
, false - в виде массива.
Организация конфигураций приложения
В приложении полезно разделять конфигурацию на несколько файлов, объединяя ее во время использования. Группируются конфигурации по следующим правилам:
- Глобальные и модульные конфигурации - общие настройки системы, относящиеся к инфраструктуре (на пример, конфигурация доступа к базе данных), должны располагаться в файлах общих конфигураций, а прикладные конфигурации в файлах модулей
- Конфигурации разработки и развертывания - часто конфигурации для разработки и развертывания требуют различных данных, в этом случае полезно использовать два объединяемых файла конфигурации
develop
иproduction
Рассмотрим пример организации конфигураций в модульном приложении:
application/
config/ # глобальные конфигурации
config.php # общие конфигурации
production.php # конфигурации только для production
develop.php # конфигурации для разработчика
module/
Album/
config/ # модульные конфигурации
config.php # общие конфигурации
production.php # конфигурации только для production
develop.php # конфигурации для разработчика
При старте приложения необходимо объединять глобальные и модульные конфигурации, исключая production
и develop
конфигурацию в зависимости от окружения:
<?php
use Zend\Config\Factory;
// Для Production окружения
$config = Factory::fromFiles([
'application/config/config.php',
'application/config/production.php',
'application/module/Album/config/config.php',
'application/module/Album/config/production.php',
], true);
// Для Develop окружения
$config = Factory::fromFiles([
'application/config/config.php',
'application/config/develop.php',
'application/module/Album/config/config.php',
'application/module/Album/config/develop.php',
], true);
Для автоматизации процесса подключения конфигураций можно так же использовать переменные окружения:
<?php
use Zend\Config\Factory;
$config = Factory::fromFiles([
'application/config/config.php',
'application/config/' . $_ENV['env'] . '.php',
'application/module/Album/config/config.php',
'application/module/Album/config/' . $_ENV['env'] . '.php',
], true);
В таком случае при запуске сервера с переменной окружения env
, приложением будут загружены соответствующие ей конфигурации.