Глобальные настройки приложения php - PullRequest
4 голосов
/ 27 июля 2011

Я прочитал почти все вопросы, которые я нашел в StackOverflow по этой теме, но не смог найти прямой ответ.

Вот мой код:

Класс приложения

<?php
    class Application extends Settings {
        public function __construct($env, $cacheDir, $configFile) {
            self::$_env = $env;
            self::$_cacheDir = $cacheDir;
            self::$_config = $this->loadConfig($configFile) // reads configs from xml file into Config object
        }

        // other methods
    }
?>

Класс настроек:

<?php
class Settings {
    protected static $_env = null;
    protected static $_cacheDir = null;
    protected static $_config = null;

    public static function getEnv() {
        return self::$_env;
    }

    public static function getCacheDir() {
        return self::$_cacheDir;
    }

    public static function getConfig() {
        return self::$_config;
    }
}
?>

Я обращаюсь к настройкам из любого места в моем коде, например:

<?php
var_dump(Settings::getEnv());
?>

Я хочу получить доступ к настройкам из разных мест.Все значения могут быть установлены только один раз и не могут быть перезаписаны (поэтому реестр с методами __set не работает, потому что я могу установить любое значение из любого места на любой стадии процесса приложения)

Вопросы:

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

Спасибо за ваши ответы

Ответы [ 3 ]

4 голосов
/ 28 июля 2011

Как указал Виккен в комментарии к вашему вопросу, вы представляете Global State для своего приложения. Цитируя Мартина Фаулера о глобальном состоянии (PoEAA, стр. 482f):

Помните, что любые глобальные данные всегда виновны, пока не доказано невиновность.

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

Теперь для лучшей альтернативы

Предположим, вы перенаправили весь трафик на index.php. Затем вы можете просто загрузить / собрать все компоненты, необходимые для выполнения запроса внутри этого файла. Например, вот так:

spl_autoload_register(
    function($className) {
        static $classMap = array(
            'request' => '/path/from/here/to/Request.php',
             … more mapping
        );
        require __DIR__ . $classMap[strtolower($className)];
    }
);

$config  = parse_ini_file(__DIR__ . '/path/from/here/to/config.ini');
foreach($config['env'] as $key => $val) {
    ini_set($key, $val);
}

$router = new Router;
$router->registerActionForRoute(
    '/product/list', 
    function($request, $response) use ($config) {
        return new ProductListAction(
            $request, $response
            new ProductMapper(
                new ProductGateway(
                    new MySqli($config['db']['host'], …),
                    new Cache($config['cache'], …)
                ),
                new ProductBuilder;
            )
        );
    }
);
$router->registerActionForRoute(…);
$router->execute(new Request($_GET, $_POST, $_SERVER), new Response);

Конечно, вы скорее хотите включить автозагрузчик из отдельного файла (потому что вы хотите автоматически сгенерировать его с чем-то вроде https://github.com/theseer/Autoload). И, конечно, вы можете заменить замыкания в маршрутизаторе на Builder или фабричные паттерны. Я просто использовал простейшую возможную вещь . Это (надеюсь) легче понять таким образом. Вы можете проверить http://silex -project.org / для микро- фреймворк с использованием более сложного, но схожего подхода.

Основным преимуществом этого подхода является то, что каждый компонент с самого начала получает то, что ему нужно, через Внедрение зависимости . Это облегчит модульное тестирование вашего кода, потому что намного проще смоделировать зависимости и добиться изоляции тестов.

Еще одним преимуществом является то, что вы разделяете граф построения и график сотрудничества, поэтому вы не путаете эти ответственность (как вы бы сделали с Singleton или иным образом добавив ключевое слово new в классы, которые должны быть информационными экспертами.

1 голос
/ 27 июля 2011

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

class Settings {
    // public to simplify example, you can add setters and getters
    public $_env = null;
    public $_cacheDir = null;
    public $_config = null;
}

class Application {
    protected $config;

    public function setConfig($config) {
        $this->config = $config;
    }

}



$app = new Application();

$config = new Settings();

$config->_env = 'dev';
$config->_cacheDir = '/my/dir';
$config->_config = array(/* Config here */);

$app->setConfig($config);

Как уже упоминалось в другом ответе marcelog, вы можете использовать класс начальной загрузки для управления внедрением конфигурации, а также другиеобъектов, в ваш Application класс.

Базовый пример класса начальной загрузки:

class Bootstrap {

    protected $application;

    public function __construct(Application $app) {
        $this->application = $app;
    }

    // connivence method
    public function init() {
        $this->initSettings();
    }

    public function initSettings() {
        $settings = new Settings();
        $settings->_env = 'dev';
        $settings->_cacheDir = '/my/dir';

        $config = array(); // load config from file here
        $settings->_config = config;
        $this->application->setSettings($settings);
    }

    // other init methods
}

$app = new Application();

$bootstrap = new Bootstrap($app);

$bootstrap->init();

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

1 голос
/ 27 июля 2011

Можете ли вы опубликовать еще код? просто чтобы показать, как вы получаете доступ к этим настройкам.

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

он также может создавать экземпляр объекта Settings, который должен быть одноэлементным.

в объекте «Настройки» вы можете использовать магические методы (__call, __get) для доступа к различным настройкам, таким как Settings :: getSettings () -> getConfigDirectory (). Этот магический метод удалит слово «get» из вызова и попытается назначить ресурс с заданным именем (в данном случае это параметр с именем «ConfigDirectory»).

Это похоже на то, что Zend Framework делает в своих классах Zend_Application, Zend_Bootstrap и Zend_Config, вы можете проверить их, чтобы получить некоторые идеи.

В качестве примечания, я не вижу (концептуально говоря), почему приложение должно расширять настройки. У приложения должны быть некоторые настройки, но они сильно отличаются от расширения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...