CORE
![]() |
Эта статья является демонстрацией примера приведенного в статье Registry |
|---|
![]() |
У этой статьи есть продолжение Pattern: Registry |
|---|
Как и было условлено ранее, класс должен реализовывать паттерн Singleton, чтобы исключить возможность создания его копии.
class CORE{
private $tools;
private static $instance;
final private function __construct(){
echo "CORE::__construct()\n";
}
static function & __instance(){
if (!isset(self::$instance))
self::$instance = new self;
return self::$instance;
}
function __clone(){
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
}
Теперь создать объект напрямую оператором new не получиться, а клонирование вызовет ошибку уровня E_USER_ERROR.
Свойство tools будет хранить в себе ссылки на все управляемые объекты, а instance ссылку на само ядро. Добавим методы регистрации и разнрегистрации объектов в ядре.
static function & register($tool, $name=''){
if (is_string($tool) && !$name)
$name = $tool;
if (self::has($name))
throw new Exception("Try to re-register tool '$name'",1);
$instance = self::__instance();
$instance->tools[$name] = $instance->factory($tool);
return $instance->tools[$name];
}
static function unregister($name, $force=false){
if (!self::has($name))
throw new Exception("Try to unregister non-existing tool '$name'",1);
$instance = self::__instance();
unset($instance->tools[$name]);
if ($force && is_callable(array($name,"kill")))
call_user_func(array($name,"kill"));
}
Здесь метод register принимает первым параметром объект или название класса из которого этот объект можно создать, а вторым имя под которым его нужно будет сохранить.
Метод unregister принимает название объекта который нужно уничтожить и флаг для форсирования уничтожения объекта.
Помимо этого используються еще два метода: has и factory, has проверяет не зарегистрирован ли уже объект с таким именем, а factory создает объект если указано только его название.
static function has($name){
$instance = self::__instance();
if (isset($instance->tools[$name]))
return true;
return false;
}
static function & factory($name){
if (is_object($name))
return $name;
if (!class_exists($name) && is_callable("__autoload"))
__autoload($name);
if (class_exists($name)){
if(is_callable(array($name,"__instance")))
return $instance->tools[$name] = call_user_func(array($name,"__instance")); // метод $name::__instance вызван статично
return $instance->tools[$name] = new $name;
}
throw new Exception("Class '$name' doesn't declared and can't be loaded!");
}
Немного подробнее о методе factory: он пытается создать экземпляр класса, когда известно только имя этого класса. Если такой класс не найден, то метод передает управление функции __autoload. Затем снова проверяет, доступен ли класс. Если не доступен, то бросает exception, а если доступен, то пытается создать его либо непосредственно используя оператор new, либо как паттерн Singleton используя метод __instance. При этот метод __instance вызывается статично!
Помимо всего этого нужен еще один метод, для доступа ко всему тому, что было зарегистрировано.
static function & extract($name){
if (!self::has($name))
self::factory($name);
$instance = self::__instance();
return $instance->tools[$name];
}
И заканчивает описание класса деструктор, который будет уничтожать объекты в обратном порядке их регистрации:
function __destruct(){
$instance = self::__instance();
$tools = array_reverse(array_keys($instance->tools),true);
foreach ($tools as $name){
echo "Вызыв. деструктор $name\n";
self::unregister($name,true);
}
echo "Объект разрушен CORE\n";
}
Теперь приведу пример работы с этим классом:
class B
{
private static $instance;
final private function __construct(){
echo "B::__construct()\n";
}
static function & __instance(){
if (!isset(self::$instance))
self::$instance = new self;
return self::$instance;
}
public function kill(){
self::$instance = null;
}
public function __destruct(){
echo "Объект разрушен B\n";
}
}
class C
{
public $B;
public function __construct($B){
echo "C::__construct()\n";
$this->setB($B);
}
public function setB($B){
$this->B = $B;
}
public function __destruct(){
echo "Объект разрушен C\n";
}
}
CORE::__instance();
CORE::register('B');
CORE::register(new C(CORE::extract('B')),'C');
/** RESULT ********
CORE::__construct()
B::__construct()
C::__construct()
Вызыв. деструктор C
Объект разрушен C
Вызыв. деструктор B
Объект разрушен B
Объект разрушен CORE
********************/

Свежие комментарии