ОК, допустим, вы хотите загрузить конфигурацию скрипта. Эта конфигурация может быть сохранена в файле базы данных / XML / INI / YAML. Каждый драйвер должен реализовывать некоторый интерфейс, назовем его ConfigurationLoader
.
interface ConfigurationLoader {
public function load();
public function get($key, $default = null);
}
// The final usage of the code:
$configuration = new XMLConfiguration('./some/file.xml');
$configuration = new YAMLConfiguration('./some/file.yaml');
$configuration = new DatabaseConfiguration($dbHandler, 'table_name');
$configuration->load();
echo $configuration->get('abc.def.ghi');
Итак, теперь нам нужно реализовать наши драйверы. Первое, что вы должны заметить, это то, что файловые драйверы, вероятно, работают одинаково. Разница лишь в том, что каждый из них разбирает исходные файлы по-своему. С другой стороны, драйвер базы данных работает совершенно иначе.
class DatabaseConfiguration implements ConfigurationLoader {
protected $config = array();
protected $pdo, $tableName;
public function __construct(PDO $dbHandler, $tableName) {
$this->pdo = $pdo;
$this->tableName = $tableName;
}
public function load() {
$this->config = /* fetch data from database */;
}
public function get($key, $default = null) {
return array_key_exists($this->config, $key) ? $this->config[$key] : $default;
}
}
Теперь нам нужно реализовать драйверы XML, INI и YAML. Все они работают почти одинаково, поэтому ... давайте создадим некоторый абстрактный класс, который будет обрабатывать общий код:
abstract class FileConfiguration implements ConfigurationLoader {
// Each file-based configuration loader has a constructor that takes file name as first argument
protected $filename;
public function __construct($filename) {
$this->filename = $filename;
$this->getFileContents();
}
// Each file-based driver has to store file content
protected $fileContent;
protected function getFileContents() {
$this->fileContents = file_get_contents($this->filename);
}
// Each driver will have to implement its own implementation of load().
// XMLConfiguration will parse XML, INIConfiguration will parse INI etc.
abstract public function load();
// However all of them will store parsed configuration in $config array:
protected $config = array();
public function get($key, $default = null) {
return array_key_exists($this->config, $key) ? $this->config[$key] : $default;
}
}
FileConfiguration
должен быть абстрактным, потому что он не знает, как анализировать содержимое файла. Только поставленные классы знают, как это сделать:
class XMLConfiguration extends FileConfiguration {
public function load() {
$xml = simplexml_load_string($this->fileContents);
foreach ($xml->root as $config) {
$this->config[(string) $config->key] = (string) $config->value;
}
}
}
class YAMLConfiguration extends FileConfiguration {
public function load() {
$yaml = new SomeYAMLParser($this->fileContents);
foreach ($yaml->parse() as $config) {
$this->config[$config['key']] = $config['value'];
}
}
}
class INIConfiguration extends FileConfiguration {
public function load() {
...
}
}
Как вы можете видеть в этом примере, может быть даже еще один абстрактный класс AbstractConfiguration
, который будет хранить свойство $config
и метод get($key, $default = null)
, и это будет родительский класс для DatabaseConfiguration
и FileConfiguration
.