Реализация
Реализация может быть различой, я же сделал ее удобной для себя.
<?php /** * Класс «Registry» хранит глобальные переменные и должен быть передан во все объекты. * Класс защищен от повторного создания с помощью шаблона проектирования «Singleton». */ final class Registry { private $vars = array(); // массив переменных // Singleton ---------------------------------------------------- static private $instance = NULL; // инстанс класса // создание и получение инстанса static function instance() { if (self::$instance == NULL) { self::$instance = new Registry(); }; return self::$instance; } // скрытие конструктора и клонирования private function __construct() {} private function __clone() {} // -------------------------------------------------------------- // публичные функции -------------------------------------------- // сохранение function set($name, $value = NULL, $type = 'simple') { if (!is_string($name)) { $this->errors('arg', 1, __METHOD__, 'string', gettype($name)); return false; }; // установка переменной switch ($type) { case 'protected': if (!isset($this->vars[$name]) || (isset($this->vars[$name]) && $this->vars[$name]['type'] == 'simple')) { $this->vars[$name] = array( 'value' => $value, 'type' => $type ); return true; } else { $this->errors('var', 0, $name, __METHOD__); return false; }; case 'simple': if (isset($this->vars[$name]) && $this->vars[$name]['type'] == 'protected') { $this->errors('var', 0, $name, __METHOD__); } else { $this->vars[$name] = array( 'value' => $value, 'type' => $type ); return true; }; default: $this->errors('var', 2, $name, __METHOD__); return false; }; } // получение function get($name) { if (!is_string($name)) { $this->errors('arg', 1, __METHOD__, 'string', gettype($name)); return false; }; if (isset($this->vars[$name])) { return $this->vars[$name]['value']; } else { $this->errors('var', 1, $name, __METHOD__); return false; } } // -------------------------------------------------------------- // ошибки (приватная функция) ----------------------------------- private function errors($type) { switch ($type) { case 'arg': // инициализация аргументов $number = func_get_arg(1); $method = func_get_arg(2); $must = func_get_arg(3); $given = func_get_arg(4); $call = debug_backtrace()[1]; trigger_error("argument <i>$number</i> passed to <i>$method()</i> must be an instance of <u>$must</u>, <u>$given</u> given, called in <b>" . $call['file'] . "</b> on line <b>" . $call['line'] . "</b> and defined", E_USER_WARNING); break; case 'var': // инициализация аргументов $error = func_get_arg(1); $name = func_get_arg(2); $method = func_get_arg(3); // ошибки $errors = array( array( 'value' => "protected variable <i>$name</i> passed to <i>$method()</i> has already been registered", 'type' => E_USER_ERROR ), array( 'value' => "variable <i>$name</i> passed to <i>$method()</i> has not been registered", 'type' => E_USER_WARNING ), array( 'value' => "type of variable <i>$name</i> passed to <i>$method()</i> must be <u>simple</u> or <u>protected</u>", 'type' => E_USER_WARNING ) ); $call = debug_backtrace()[1]; trigger_error($errors[$error]['value'] . ", called in <b>" . $call['file'] . "</b> on line <b>" . $call['line'] . "</b> and defined", $errors[$error]['type']); break; }; } // -------------------------------------------------------------- } ?>
“Singleton“
Во избежание копирования или создания нового инстанса, нужно применить шаблон “Singleton“. Это поможет избежать проблем с доступом к переменным.
// Singleton ---------------------------------------------------- static private $instance = NULL; // инстанс класса // создание и получение инстанса static function instance() { if (self::$instance == NULL) { self::$instance = new Registry(); }; return self::$instance; } // скрытие конструктора и клонирования private function __construct() {} private function __clone() {} // --------------------------------------------------------------
Для того, чтобы получить инстанс класса Registry, который защищен этим способом, нужно вызвать метод Registry::instance()
, который возвращает объект, если он существует, в противном случае предварительно его создав. Создать объект снаружи класса через оператор new или клонировать невозможно. Т.к. этот метод статичен, его можно вызвать в любом месте кода и, как следствие, получить объект класса Registry.
Хранение значений
Класс позволяет хранить два типа переменных — защищенные (protected) и обычные (simple). Защищенные переменные невозможно изменить после создания, а обычные — возможно.
Установка значений
bool Registry::set(string $name, mixed $value [, string $type])
Где $name
— имя переменной, $value
— значение переменной, $type
— необязательный тип переменной (по умолчанию 'simple'
). Вернет true, в случае успешного добавления, и false, в случае ошибки. Если Вы попробуете переписать защищенную переменную, то будет выведена ошибка.
Получение значений
mixed Registry::get(string $name)
Где $name
— имя переменной. Возвращает значение переменной $name
или false, в случае ошибки. При попытке получить несуществующую переменную будет выведена ошибка.
Пример
// получение инстанса $registry = Registry::instance(); // установка защищенной переменной $registry->set('protected_var', 'This variable is protected', 'protected'); // установка обычной переменной $registry->set('simple_var', 'This variable is simple'); echo $registry->get('protected_var'); // => 'This variable is protected' echo $registry->get('simple_var'); // => 'This variable is simple' echo $registry->get('var'); // => false // перезаписывание значения обычной переменной $registry->set('simple_var', 'Rewrite simple variable'); // перезаписывание значения защищенной переменной обернется ошибкой $registry->set('protected_var', 'Rewrite protected variable');
Ошибки
Класс имеет встроенный вывод ошибок, использующий функцию trigger_error(). Ниже приведены все возможные ошибки и их тип.
Тип | Ошибка | Значение |
E_USER_ERROR | protected variable test_var passed to Registry::set() has already been registered, called in /test.php on line 10 | Нельзя изменять значение защищенной переменной test_var. |
E_USER_WARNING | variable test_var2 passed to Registry::get() has not been registered, called in /test2.php on line 5 | Вы пытаетесь получить значение несуществующей переменной test_var2. |
E_USER_WARNING | type of variable test_var3 passed to Registry::set() must be simple or protected, called in /test3.php on line 7 | Вы указали неверный тип переменной test_var3, он может быть либо simple, либо protected. |
E_USER_WARNING | argument 1 passed to Registry::set() must be an instance of string, array given, called in /test4.php on line 6 | Первый аргумент метода Registry::set() должен быть строкой, Вы пытаетесь передать массив. |
Заключение
Благодаря этому шаблону проектирования, в конструкторах классов, которые вызываются фасадом в моей системе, я могу получить и сохранить необходимые для работы объекты, которые я создавал ранее (например, шаблонизатор Smarty мне нужен практически везде). Существование защищенных переменных гарантирует мне, что я нигде не перепишу их значение и не положу из-за этого работу всего сайта, а защита объекта шаблоном Singleton гарантирует, что сохраненные переменные не потеряются. Мне кажется это очень удобным и хорошим способом хранить важные глобальные данные и получать их в любом месте кода.
ссылка на оригинал статьи http://habrahabr.ru/post/166359/
Добавить комментарий