<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CTAPbIu_MABP&#039;s BLOG &#187; pattern</title>
	<atom:link href="http://mabp.kiev.ua/tag/pattern/feed/" rel="self" type="application/rss+xml" />
	<link>http://mabp.kiev.ua</link>
	<description>энтузиазм = 1/опыт © Старый Мавр</description>
	<lastBuildDate>Sat, 12 May 2012 07:40:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2</generator>
		<item>
		<title>Pattern: Decorator</title>
		<link>http://mabp.kiev.ua/2009/08/03/pattern-decorator/</link>
		<comments>http://mabp.kiev.ua/2009/08/03/pattern-decorator/#comments</comments>
		<pubDate>Mon, 03 Aug 2009 21:35:36 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1097</guid>
		<description><![CDATA[Сколько раз обещаю себе больше не писать на PHP, и всеравно пишу. Вот и недавно разродился небольшим классом реализующим шаблон декоратор. class Decorator { protected $obj; public function __construct($name,$args=null){ if (is_object($name)) { $this->obj = $name; } else if($args) { $reflection = new ReflectionClass($name); $this->obj = $reflection->newInstanceArgs($args); } else { $this->obj = new $name; } } [...]]]></description>
			<content:encoded><![CDATA[<p>Сколько раз обещаю себе больше не писать на <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a>, и всеравно пишу. Вот и недавно разродился небольшим классом реализующим шаблон декоратор.</p>
<span id="more-1097"></span>
<pre><code class="php">
class Decorator {
	protected $obj;
	public function __construct($name,$args=null){
		if (is_object($name)) {
			$this->obj = $name;
		} else if($args) {
			$reflection = new ReflectionClass($name);
			$this->obj = $reflection->newInstanceArgs($args);
		} else {
			$this->obj = new $name;
		}
	}

	public function __call($name,$args){
		if($args)
			return call_user_func_array(array($this->obj,$name), $args);
		else
			return $this->obj->{$name}();
	}
}
</code></pre>

<p>Все началось как пример <a href="http://pyha.ru/forum/topic/3067.msg61203#msg61203" rel="nofollow external">одному долбаёбу на форуме</a>, а закончилось как небольшой но прикольный класс. Естественно сначала я пару раз переписал пример, потом потестил его на локальном сервере и только потом написал эту статью, так что в классе есть небольшие изменения.</p>

<p>На вопрос нах вообще нуже декоратор я отвечать не буду - читайте вики или еще что-то. А вот на вопрос как это работает отвечу. Для начала создадим класс который нужно декорировать.</p>

<pre><code class="php">
class MyClass {
	private $property;
	public function __construct($property){
		$this->property = $property;
	}
	public function printMethodName(){
		echo __METHOD__;
	}
	
	public function printMyArgument($arg){
		echo $arg;
	}
	
	public function printMyProperty(){
		echo $this->property;
	}
	public function myDecoratedMethod(){
		echo "Decorated Method!";
	}
}
</code></pre>

<p>Как понятно методы особой смысловой нагрузки не несут, а только показывают что были вызваны именно они. Теперь создадим класс производный от декоратора, который будет декорировать последний метод класса MyClass.</p>

<pre><code class="php">
class ConcreteDecorator extends Decorator {
	public function myDecoratingMethod(){
		return $this->myDecoratedMethod();
	}
}
</code></pre>

<p>Теперь это все можно использовать примерно вот таким образом:</p>

<pre><code class="php">
$myObj = new ConcreteDecorator("MyClass", array("String passed via constructor"));

$myObj->printMyProperty();
$myObj->printMethodName();
$myObj->printMyArgument("String passed via printMyArgument");
$myObj->myDecoratingMethod();
</code></pre>

<p>Но что-то как-то некрасиво получается, надо бы добавить в после каждого метода обрыв строки, для этого создадим еще один декоратор:</p>

<pre><code class="php">
class MyNewLineDecorator extends Decorator {
	public function __call($name,$args){
		parent::__call($name,$args);
		echo "&lt;br /&gt;";
	}
}
</code></pre>

<p>И добавим его в код.</p>

<pre><code class="php">
$myObj = new ConcreteDecorator("MyClass", array("String passed via constructor"));
$myObj = new MyNewLineDecorator($myObj);

$myObj->printMyProperty();
$myObj->printMethodName();
$myObj->printMyArgument("String passed via printMyArgument");
$myObj->myDecoratingMethod();
</code></pre>

<p>В результате получаем:</p>
<pre>
String passed via constructor&lt;br /&gt;
MyClass::printMethodName&lt;br /&gt;
String passed via printMyArgument&lt;br /&gt;
Decorated Method!&lt;br /&gt;
</pre>

<p>Приятного использования.</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/08/03/pattern-decorator/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Pattern: Singleton</title>
		<link>http://mabp.kiev.ua/2009/04/04/pattern-singleton/</link>
		<comments>http://mabp.kiev.ua/2009/04/04/pattern-singleton/#comments</comments>
		<pubDate>Fri, 03 Apr 2009 23:01:26 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=999</guid>
		<description><![CDATA[Шаблон проектирования Singleton (одиночка) используется для того чтобы класс можно было создать только один раз. На практике он применяется вместе с другим шаблонами проектирования такими как pattern Registry и pattern ServiceLocator class Singleton { private static $instance; // object /** * Private constructor does nothing * */ final private function __construct(){ /* ... */ } [...]]]></description>
			<content:encoded><![CDATA[<p>Шаблон проектирования Singleton (одиночка) используется для того чтобы класс можно было создать только один раз. На практике он применяется вместе с другим шаблонами проектирования такими как <a href="http://mabp.kiev.ua/2008/04/17/pattern_registry/">pattern Registry</a> и <a href="http://mabp.kiev.ua/2008/05/02/pattern_service_locator/">pattern ServiceLocator</a></p>
<span id="more-999"></span>

<pre><code class="php">
class Singleton {
	private static $instance; // object

	/**
	 * Private constructor does nothing
	 *
	 */
	final private function __construct(){
		/* ... */
	}

	/**
	 * Return the single instance of object
	 *
	 * @return object
	 */
	public static function &#038; __instance(){
		if (!isset(self :: $instance))
			self :: $instance = new self;
		return self :: $instance;
	}
}

$single = Singleton::__instance();
</code></pre>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/04/04/pattern-singleton/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pattern: ServiceLocator</title>
		<link>http://mabp.kiev.ua/2008/05/02/pattern_service_locator/</link>
		<comments>http://mabp.kiev.ua/2008/05/02/pattern_service_locator/#comments</comments>
		<pubDate>Fri, 02 May 2008 16:04:39 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=205</guid>
		<description><![CDATA[Статья Pattern: Registry имеет непосредственно отношение к этой статье, советую ознакомиться перед прочтением. Паттерн ServiceLocator изначально спроектирован для Java и дает возможность находить сервисы, зная их имя. В Java для того чтоб найти Enterprise JavaBeans (EJB) или Java Message Service (JMS) нужно использовать JNDI API. Это накладывает на код некоторые ограничения, например операции поиска и [...]]]></description>
			<content:encoded><![CDATA[<table style="background-color:#EDEFF0;width:100%;"><tbody><tr><th><img src="/wp-content/themes/inove/img/warning_yellow.png"/></th>
<th style="text-align: center;">Статья <a href="http://mabp.kiev.ua/2008/04/17/registry/" title="Pattern: Registry">Pattern: Registry</a> имеет непосредственно отношение к этой статье, советую ознакомиться перед прочтением.</th></tr></tbody></table>

<p>Паттерн ServiceLocator изначально спроектирован для Java и дает возможность находить сервисы, зная их имя. В Java для того чтоб найти Enterprise JavaBeans (EJB) или Java Message Service (JMS) нужно использовать JNDI API. Это накладывает на код некоторые ограничения, например операции поиска и создания компонентов служб могут быть сложными (ресурсоемкими) и могут использоваться периодически в различных клиентах приложения. Для этого ввели паттерн, который позволяет абстрагироваться от использования JNDI и скрытия сложностей создания исходного контекста, а также может повторно использоваться несколькими клиентами.</p>
<span id="more-205"></span>
<p>Но поскольку для PHP это все недоступно, мы будем искать объекты для одного клиента, абстрагируясь от их создания и места расположения классов их описывающих. Мы будем использовать ту же модель иерархии и связей, что и Java но с поправками на угловатости PHP. </p>
<p>На картинке изображена диаграмма последовательности действий, показывающая взаимодействия между различными участниками ServiceLocator</p>

<img src="/content/img/servicelocator.gif" alt="Диаграмма взаимодействия между участниками ServiceLocator">

<p>Итак задача получить объект страницы для дальнейшего использования, зная только название объекта.</p>
<p>Для этого нам понадобиться четыре класса и три исключения порождаемых этими классами. Я думаю, начать стоит именно с этих трех исключений, поскольку смысловой нагрузки они пока не несут, а являются лишь абстракциями для дальнейшей реализации и внесены в код для его схожести с Java.</p>

<pre><code class="php">
class ServiceLocatorExeption extends  Exception{
}

class InitialContextException extends  Exception{
}

class PageFactoryExeption extends  Exception{
}
</code></pre>

<p>Далее я бы хотел начать с конца, потому что чем дальше от начала тем сильнее уровень абстракции и меньше кода. Поэтому сервис (объект), который мы собственно пытаемся получить, в примере не имплементирует никаких интерфейсов и не расширяет никаких классов и не имеет никаких методов, а буквально состоит из своего названия. Это вполне достаточно чтобы удачно создать его экземпляр и вернуть клиенту. Кстати роль клиента тоже весьма условна, ее играет сам PHP скрипт и из-за того, что после завершения скрипта все объекты разрушаются нельзя говорить ни о каком повторном использовании созданных объектов. Единственным способом что-то использовать повторно является кэширование, основанное на БД или файлах или сессии, но при текущей задаче это слушком дорогая (время и ресурсоемкая) процедура и она не рассматривается.</p>

<pre><code class="php">
class WhitePage{

}
</code></pre>

<p>Как понятно из названия искать мы будем объект страницы, возможно чтобы ассоциировать с ним какой-то контент, а возможно для того чтобы передать его шаблонизатору для отображения.</p>
<p>Второй объект с конца у нас фабрика которая должна создать или найти уже готовый объект страницы. Лично мое мнение, что фабрика должна быть статическим классом (классом в котором все методы статические), и через конструктор вообще не должна создаваться. Но в этом примере она будет именно создаваться, а еще и получая параметры, пришедшие в виде контекста.</p>

<pre><code class="php">
class PageFactory{
	public $initialContext = null;
	
	public function __construct($initialContext){
		$this->initialContext = $initialContext;
	}
	
	public function &#038; factory(){
		try{
			// do somethind depends on $initialContext
			$product =  new WhitePage();
		}catch (Exception $e){
			throw new PageFactoryExeption();
		}
		
		return $product;
	}
}
</code></pre>
<p>Единственный метод (кроме конструктора) этой фабрики основываясь на пришедшем контексте должен выбрать какой объект он будет создавать, это может быть страница с текстом страница с уведомлением об ошибке, список страниц, или список списков. на данный момент это не важно поскольку у нас есть только "белая страница" с которой можно будет сделать все что угодно, даже распечатать и повесить в туалете.</p>
<p>Соответственно если создание не удалось, то бросается исключение, которое потом будет проброшено в сам ServiceLocator.</p>

<p>Идем дальше по цепочке. Следующий у нас объект InitialContext, который при создании должен получать в себя все доступные переменные окружения, и тоже имеет один метод (естественно кроме конструктора) который осуществляет поиск нужной фабрики и передаче ей переменных окружения, сама же фабрика возвращается в сам ServiceLocator.</p>

<pre><code class="php">
class InitialContext{
	private $data;
	public function __construct(){
		 // do something depends on 
		 // $_GET, $_POST, $_COOKIE, $_FILES, $_SESSION, etc
		 if(isset($_SESSION))
		 	$this->data = $_SESSION;
		 else 
		 	$this->data = $_REQUEST;
	}
	
	public function &#038; lookup($name){
		$factoryName = ucfirst($name)."Factory";
		try{
			$factory = new $factoryName($this->data);	
		}catch (Exception $e){
		/*
			try{
				$factoryName::getInstance();
			}catch(Exception $ee){
				throw new InitialContextException();
			}
		*/
			throw new InitialContextException();
		}
		return $factory;
	}
}
</code></pre>

<p>Тут очень хотелось в блоке catch сделать еще один try для попытки получения инстанса у синглтон объекта, но его пришлось закомментировать потому что PHP поддерживает конструкцию $factoryName::getInstance() только начиная с версии 5.3. В предыдущих версиях название класса должно быть указанно непосредственно. Разработчики объясняют это тем, что при начале синтаксического разбора все статические вызовы преобразуются в функции.</p>

<p>Ну и наконец то мы добрались до сладенького. То есть до самой реализации ServiceLocator. По наставлению Java класс реализовывает <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a> и имеет метод getService принимающий название сервиса и возвращающий сам сервис. Больше пока ничего нет, да ничего и не будет, наверное, потому что получать id объекта, а потом восстанавливать его по этому id неоткуда.</p>

<pre><code class="php">
class ServiceLocator{
	private static $instance = null;
	private static $initialContext = null;

    final private function __construct(){
    	try {
    		$this->initialContext = new InitialContext();
    	}catch (Exception $e){
    		throw new ServiceLocatorExeption();	
    	}
    } 
	
	static function &#038; getInstance(){ 
        if (!isset(self :: $instance)) 
            self :: $instance = new self; 
        return self :: $instance; 
    }
	
	public function &#038; getService($name){
		if (empty($name))
			throw new ServiceLocatorExeption();
		
		try{
			$serviceFactory = $this->initialContext->lookup($name);
			$service = $serviceFactory->factory();
		}catch (InitialContextException $e){
			throw new ServiceLocatorExeption();
		}catch (PageFactoryExeption $e){
			throw new ServiceLocatorExeption();
		}

		return $service;	
	}
}
</code></pre>

<p>Ну я думаю тут тоже ничего сложного нет. Приватный конструктор при единственном вызове создает InitialContext и сохраняет его. getInstance обеспечивает доступ к инстансу, а getService запускает всю вышеописанную цепочку и возвращает нам нашу белую страничку. Для запуска все этого добра требуется всего две строчки:</p>

<pre><code class="php">
$serviceLocator = ServiceLocator::getInstance();
var_dump($serviceLocator->getService("page"));
// object(WhitePage)#4 (0) { }
</code></pre>

<p>Вообще эта статья была написана в поисках того как можно объединить <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерн Registry</a> и Pattern ServiceLocator. Вышло следующее, но реально применять на сайте я пока не стал из-за отсутствия наличия PHP 5.3 на сервере.</p>

<pre><code class="php">

class PageFactory{
	public $initialContext = null;
	
	public function __construct(){
		 if(isset($_SESSION))
		 	$this->initialContext = $_SESSION;
		 else 
		 	$this->initialContext = $_REQUEST;
	}
	
	public function &#038; factory(){
		try{
			// do something depends on $initialContext
			$product =  new WhitePage();
		}catch (Exception $e){
			throw new PageFactoryExeption();
		}
		
		return $product;
	}
}

</code></pre>

<p>Классом InitialContext я пожертвовал, решив, что он лишний в этой пищевой цепочке и переложил его функции частично на класс PageFactory и частично на ServiceLocator::factory. Новый ServiceLocator основан на всем, что было в <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерн Registry</a>, по сути, добавляя только один новый метод getObjId. Метод getService является синонимом register с той лишь разницей, что добавляет уникальный идентификатор и дает хранить несколько объектов одного типа. Метод getObj это обертка для extract. А вот метод getObjId это уникальная плюшка класса ServiceLocator которая дает возможность получать id имея объект, операция противоположная для getObj. И, наконец переписан метод factory добавляя дополнительную возможность создания объекта через его фабрику. Например, если есть page но не известно как его создать сначала будет создана фабрика PageFactory, а потом будет попытка создать из нее что-нибудь, используя метод factory.</p>

<pre><code class="php">
require_once("class.registry.php");

class ServiceLocator extends Registry {

	/**
	 * Looks up for services
	 *
	 * @param string $name
	 * @return mixed
	 */
	static public function &#038; getService($name){
		$id = md5(time());
		$service = self::register($name,$id);
		return $service;
	}

	/**
	 * Restore object by id
	 *
	 * @param string $id
	 * @return mixed
	 */
	static public function &#038; getObj($id){
		return self::extract($id);	
	}	
	
	/**
	 * extracts object id
	 *
	 * @param mixed $obj
	 * @return string
	 */
	static public function &#038; getObjId($obj){
		$reg = self::__instance();
		// array_search($obj, $reg->tools) ???
		foreach ($reg->tools as $key => &#038;$val)
			if($obj === $val)
				break;
		return $key;
	}
	
	/**
	 * Implementation of factory pattern
	 *
	 * @param string $name
	 * @param array $param
	 * @param string $func
	 * @return object
	 */
	static public function &#038; factory($name,$params=null,$func="__instance"){
		
		if (is_object($name)) 
			return $name;
		
		if (!class_exists($name) &#038;& is_callable("__autoload"))
			__autoload($name);
		
		if (class_exists($name)){
			if(is_callable(array($name,$func))){
				return call_user_func_array(array($name,$func),$params); // метод $name::$func вызван статично
			}else if(!$params){ // пытаемся сэкономить время
				return new $name();
			}else{
				$reflection = new ReflectionClass($name);
				return $reflection->newInstanceArgs($params);
			}
		}else{
			$factory = ucfirst($name)."Factory";
			
			if (!class_exists($factory) &#038;& is_callable("__autoload"))
				__autoload($factory);

			if(class_exists($factory) &#038;& is_callable(array($factory,"factory"),true)){
				return call_user_func_array(array($factory,"factory"),$params);
			}
		}
		// если мы до сюда дошли и ничего не вернули то бросаем исключение
		throw new Exception("Class '$name' doesn't declared and can't be loaded so does it's factory");

	}
}
</code></pre>

<p>Прежде чем вы попробовали запустить этот код, спешу заметить что работать код будет только на PHP 5.3, хотя сам я пока не проверял. По причине указанной выше статические методы классов наследников не перезаписывают статические методы классов родителей. Для того чтобы пример заработал нужно добавить новые методы в класс <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерн Registry</a> и переписать метод factory.</p>
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/05/02/pattern_service_locator/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pattern: Registry</title>
		<link>http://mabp.kiev.ua/2008/04/17/pattern-registry/</link>
		<comments>http://mabp.kiev.ua/2008/04/17/pattern-registry/#comments</comments>
		<pubDate>Thu, 17 Apr 2008 21:58:45 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=3</guid>
		<description><![CDATA[Подробное описание работы класса смотрите в предыдущей статье CORE. Возможно вам будет интересна статья ServiceLocator, она имеет непосредственное отношение к этой статье. Решил обновить класс, но очень не хотел переписывать прошлую статью, она мне дорога как память :). Поэтому решил еще раз опубликовать свежий класс. Напомню или расскажу для тех, кто не заметил сверху ссылки [...]]]></description>
			<content:encoded><![CDATA[<table style="background-color:#EDEFF0;width:100%;"><tbody><tr><th><img src="/wp-content/themes/inove/img/warning_yellow.png"/></th>
<th style="text-align: center;">
Подробное описание работы класса смотрите в предыдущей статье <a href="http://mabp.kiev.ua/content/2007/06/11/core/" title="CORE">CORE</a>.</th></tr></tbody></table>

<table style="background-color:#EDEFF0;width:100%;"><tbody><tr><th><img src="/wp-content/themes/inove/img/warning_yellow.png"/></th>
<th style="text-align: center;">
Возможно вам будет интересна статья <a href="http://mabp.kiev.ua/content/2008/05/02/pattern_service_locator/" title="ServiceLocator">ServiceLocator</a>, она имеет непосредственное отношение к этой статье.</th></tr></tbody></table>

<p>Решил обновить класс, но очень не хотел переписывать прошлую статью, она мне дорога как память :). Поэтому решил еще раз опубликовать свежий класс. Напомню или расскажу для тех, кто не заметил сверху ссылки на предыдущую версию, что класс реализует <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерн Registry</a>. То есть это <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">Singleton</a> класс, имеющий в себе ссылки на все основные ресурсы сайта. Например, удобно получать ссылку на объект для работы с базой данных с помощью выражения Registry::extract('db') не заботясь о том где, как и когда он был создан.</p>
<span id="more-3"></span>
<pre><code class="php">

class Registry {

	private $tools = array(); // array
	private static $instance; // object

	/**
	 * Private constructor does nothing
	 *
	 */
	final private function __construct(){
		/* ... */
	}

	/**
	 * Return the single instance of object
	 *
	 * @return object
	 */
	public static function &#038; __instance(){
		if (!isset(self :: $instance))
			self :: $instance = new self;
		return self :: $instance;
	}
	
	/**
	* Register tools
	*
	* @param object|string $tool
	* @param string $name
	* @param array $p
	* @return object
	*/
	public static function &#038; register($tool, $name='', $p=null, $f='__instance'){
		if (is_string($tool) &#038;& !$name)
			$name = $tool;
		$instance = self :: __instance();
		$instance->tools[$name] = $instance->factory($tool, $p, $f);
		return $instance->tools[$name];
	}

	/**
	 * Unregister tools
	 *
	 * @param string $name
	 * @param bool $force
	 */
	public static function unregister($name, $force=false){
		$instance = self :: __instance();
		unset($instance->tools[$name]);
		if ($force &#038;& is_callable(array($name,"__kill")))
	   		call_user_func(array($name,"__kill"));
	}

	/**
	 * Search for tool
	 *
	 * @param srting $name
	 * @return bool
	 */
	public static function has($name){
		$instance = self :: __instance();
		if (isset($instance->tools[$name]))
			return true;
		return false;
	}

	/**
	 * Factory method
	 *
	 * @param string|object $name
	 * @return object
	 */
	public static function &#038; factory($name,$params=null,$func="__instance"){

		if (is_object($name))
			return $name;

		if (!class_exists($name) &#038;& is_callable("__autoload"))
			__autoload($name);
		
		if (class_exists($name)){
			if(is_callable(array($name,$func))){
				return call_user_func_array(array($name,$func),$params); // метод $name::$func вызван статично
			}else if(!$params){ // пытаемся сэкономить время
				return new $name();
			}else{
				$reflection = new ReflectionClass($name);
				return $reflection->newInstanceArgs($params);
			}
		}
		throw new RegistryException("Class '$name' doesn't declared and can't be loaded!");

	}

	/**
	 * Access method for tools
	 *
	 * @param string $name
	 * @return object
	 */
	public static function &#038; extract($name){
		if (!self :: has($name))
			self :: factory($name);
		$instance = self :: __instance();
		return $instance->tools[$name];
	}

	/**
	 * Overload
	 *
	 * @param string $name
	 * @return object
	 */
	public function __get($name){
		return self :: extract($name);
	}

	/**
	 * Overload
	 *
	 * @param string $name
	 * @param object|string $tool
	 * @return object
	 */
	public function __set($name,$tool){
		return self :: register($tool,$name);
	}

	/**
	 * Cloning is deprecated
	 *
	 */
	public function __clone(){
		throw new RegistryException('Clone is not allowed!');
	}

	/**
	 * Destroy all tools
	 *
	 */
	public function __destruct(){
		$instance = self :: __instance();
		$tools = array_reverse(array_keys($instance->tools),true);
		foreach ($tools as $name){
			echo "Вызыв. деструктор $namen";
			self :: unregister($name,true);
		}
	}
}
</code></pre>
<p>Основные изменения коснулись фабричного метода, были добавлены новые параметры и реализовано создание класса с параметрами через конструктор, что до сих пор было не возможно. Причем старый метод создания класса без параметров остался в силу того, что работает он быстрее, чем новый основанный на рефлекции. Так  была исправлена ошибка, которая регистрировала свежесозданные объекты прямо в фабрике.</p>

<p>Из-за неудобства в использовании были убраны исключения порождаемые при попытке повторной регистрации под тем же именем и разрегистрации несуществующего объекта, теперь не придется проверять наличие/отсутствие объектов перед их заменой.</p>

<p>Еще одно нововведение - теперь класс имеет перегруженные методы <span style="color:#000000;font-weight:bold;">__set</span> и <span style="color:#000000;font-weight:bold;">__get</span>, благодаря которым практически отпадает надобность в статических методах.</p>

<p>Для демонстрации возможностей создадим два демонстрационных класса. Первый будет реализовывать <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a> а второй будет обычным.</p>

<pre><code class="php">
/**
 * Класс реализовывающий паттерн Singleton должен иметь два метода
 * __instance - для создания инстанса
 * __kill - для разрушения инстанса
 */
class B
{
	private static $instance;

	final private function __construct(){
		echo "B :: __construct()n";
	}

	static function &amp; __instance(){
		if (!isset(self :: $instance))
			self :: $instance = new self;
		return self :: $instance;
	}

	public function __kill(){
		echo "Разрушаем объект  Bn";
		self :: $instance = null;
	}

	public function __destruct(){
		echo "Объект разрушен   Bn";
	}
}
</code></pre>
<p><a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">Singleton</a> класс помимо <span style="color:#000000;font-weight:bold;">__construct</span> и <span style="color:#000000;font-weight:bold;">__destruct</span> реализовывает еще два магических метода: <span style="color:#000000;font-weight:bold;">__instance</span> для создания/получения сущности и <span style="color:#000000;font-weight:bold;">__kill</span> для уничтожения этой сущьности при разрегистрации. Напомню, что если разрегистировать класс не вызвав <span style="color:#000000;font-weight:bold;">__kill</span>, то ссылка на класс останется в нем самом, и его можно будет продолжать использовать, реальное же разрушение класса произойдет только по окончанию скрипта.</p>
<pre><code class="php">
class C
{
	public $B;

	public function __construct($B){
		echo "C :: __construct()n";
		$this-&gt;setB($B);
	}

	public function setB($B){
		$this-&gt;B = $B;
	}

	public function __destruct(){
		echo "Объект разрушен   Cn";
	}
}
</code></pre>
<p>Обычный класс, создаваемый через конструктор, не должен содержать никаких дополнительных методов, и будет разрушаться при разрегистрации сразу же если на него не осталось ссылок.</p>

<p>Демонстрация фабричного метода, без регистрации</p>
<pre><code class="php">
// Создание singleton объекта
$b = Registry::factory("B", null, "__instance");

// Или короткий способ
$b = Registry::factory("B");

// Создание обычного объекта c параметрами
$c = Registry::factory("C",array($b));
</code></pre>
<p>Демонстрация регистрации и удаления объекта</p>
<pre><code class="php">
// Создаем и регистрируем singleton объект
$b = Registry::register("B");

// Создаем и регистрируем обычный объект с параметрами
Registry::register("C","C",array($b));

// Экстрагируем объект
$c = Registry::extract("C");

// Регистрируем уже готовый объект
Registry::register($c,"D");

// Разрушаем обычный объект
Registry::unregister("D");

// Разрушаем singleton объект
Registry::unregister("B",true);

// Разрушаем ссылку на B в С
Registry::extract("C")-&gt;setB(null);

// разрушаем ссылки на объекты в глобальной области видимости
$b = $c = null;

// теперь остался один зарегистрированный экземпляр С
echo Registry::has("C");

</code></pre>
<p>А теперь внимание новинка, забудьте о двойных двоеточиях! Теперь не обязательно использовать статические методы класса <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">Registry</a>, можно с тем же успехом работать с ним как с обычным классом, присваивая и читая его свойства с помощью перегруженных <span style="color:#000000;font-weight:bold;">__set</span> и <span style="color:#000000;font-weight:bold;">__get</span>.</p>
<pre><code class="php">
// Создаем и регистрируем обычный объект
Registry::register("C");

// присваиваем инстанс класса переменной
$registry = Registry::__instance();

// читаем и пишем в свойства объекта
var_dump($registry-&gt;C);

$Registry-&gt;B = "B";
var_dump($registry-&gt;B);

$registry-&gt;D = new C(new B());
</code></pre>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/04/17/pattern-registry/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Pattern: Factory</title>
		<link>http://mabp.kiev.ua/2007/07/25/pattern_factory/</link>
		<comments>http://mabp.kiev.ua/2007/07/25/pattern_factory/#comments</comments>
		<pubDate>Wed, 25 Jul 2007 14:18:47 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=126</guid>
		<description><![CDATA[Некоторые рассуждения о шаблоне проектирования Factory, а так же примеры реализации в "домашних" условиях наиболее универсального метода. Шаблон Factory заключается в том, что метод одного объекта возвращает другой новый объект. Проиллюстрируем небольшим примером. class Factory{ public function factory(){ return new Product(); } } class Product{ } $factory = new Factory(); $product = $factory->factory(); Хотя чаще [...]]]></description>
			<content:encoded><![CDATA[<p>Некоторые рассуждения о шаблоне проектирования Factory, а так же примеры реализации в "домашних" условиях наиболее универсального метода.</p>
<span id="more-126"></span>
<p>Шаблон Factory заключается в том, что метод одного объекта возвращает другой новый объект. Проиллюстрируем небольшим примером.</p>

<pre><code class="php">
class Factory{
	public function factory(){
		return new Product();
	}
}

class Product{
}

$factory = new Factory();
$product = $factory->factory();
</code></pre>

<p>Хотя чаще фабричный метод делают статичным, но если метод нуждается в других ресурсах объекта то необходимо использовать еще и <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a>. Для этого создадим класс чуть по сложнее:</p>

<pre><code class="php">
class Factory{
	private static $instance;
	public $name = 'Product';
	
	private function __construct(){
	}

	public static function __instance(){
		if (!isset(self::$instance)){
			self::$instance = new self;
		}
		return self::$instance;
	}

	public static function factory(){
		$instance = self::__instance();
		return new $instance->name();
	}
}

class Product{
}

$product = Factory::factory();
</code></pre>

<p>Теперь предположим что конструктор <span style="color:#000;font-weight:bold;">Product</span> нуждается в параметрах, которые нужно передавать в фабричный метод.</p>

<pre><code class="php">
	// чтобы не пложить код, я заменил один метод в прошлом примере
	public static function factory($a,$b,$c){
		$instance = self::__instance();
		return new $instance->name($a,$b,$c);
	}
</code></pre>

<p>Теоретически правильно, но параметров может быть неограниченное количество (я же тут за универсализм борюсь!). </p>
<p>Казалось бы есть выход сделать это при помощи <span style="color:#000;font-weight:bold;">call_user_func_array</span> но таким образом можно вызывать только статичные методы, а конструктор не может быть статичным, поэтом делаем маленькую хитрость. При помощи встроеного класса <span style="color:#000;font-weight:bold;">ReflectionClass</span> рефлекторно вызываем нужный нам класс с параметрами.</p>

<pre><code class="php">
class Factory{
	private static $instance;
	public $name = 'Product';
	
	private function __construct(){
	}

	public static function __instance(){
		if (!isset(self::$instance)){
			self::$instance = new self;
		}
		return self::$instance;
	}

	public static function factory(){
		$instance = self::__instance();
		$args = func_get_args(); // func_get_args нельзя использовать в качестве агрумента другой функции.
		$reflection = new ReflectionClass($instance->name);
		return $reflection->newInstanceArgs($args); 
	}
}

class Product{
	public function __construct($a,$b,$c){
		echo $a,$b,$c;
	}
}

$product = Factory::factory('a','b','c');
</code></pre>

<p>Теперь мы можем вызывать любой класс с любым количеством параметров, но ведь не все классы создаются через конструктор, поэтому еще усложним задачу, предположим что некоторые объекты сами могут быть фабриками и одиночками.</p>

<pre><code class="php">
class Factory {
	private static $instance;
	
	/**
	 * Constructor
	 *
	 */
	private function __construct(){
	}
	
	/**
	 * Singleton inplementation
	 *
	 * @return object
	 */
	public static function instance(){
		if (!isset(self::$instance))
			self::$instance = new self;
		return self::$instance;
	}
	
	/**
	 * Craft new object
	 *
	 * @param string $name
	 * @param array $params
	 * @param string $func
	 * @return object
	 */
	public static function factory($name,$params=null,$func='__instance'){
		if (!class_exists($name) &#038;& is_callable("__autoload"))
			__autoload($name);
		
		if (class_exists($name)){
			if(is_callable(array($name,$func))){
				return call_user_func_array(array($name,$func),$params); // метод $name::$func вызван статично
			}else if(!$params){ // пытаемся сэкономить время
				return new $name();
			}else{
				$reflection = new ReflectionClass($name);
				return $reflection->newInstanceArgs($params);
			}
		}else{
			$factory = ucfirst($name)."Factory";
			
			if (!class_exists($factory) &#038;& is_callable("__autoload"))
				__autoload($factory);

			if(class_exists($factory) &#038;& is_callable(array($factory,"factory"),true)){
				return call_user_func_array(array($factory,"factory"),$params);
			}
		}
		// если мы до сюда дошли и ничего не вернули то бросаем исключение
		throw new FactoryException("Class '$name' doesn't declared and can't be loaded so does it's factory");
	}
}

class FactoryException extends Exception{
}

class Product1{
	public function __construct(){
		echo "Product1 &lt;br/&gt;\n";
	}
}

class Product2{
	public function __construct($a,$b,$c){
		echo 'Product2 ',$a,$b,$c," &lt;br/&gt;\n";
	}
}

class Product3{
	private static $instance;
	
	private function __construct(){
		echo "Product3 &lt;br/&gt;\n";
	}

	public static function __instance(){
		if (!isset(self::$instance)){
			self::$instance = new self;
		}
		return self::$instance;
	}
}

class Product4{
	private static $instance;
	
	private function __construct($a,$b,$c){
		echo 'Product4 ',$a,$b,$c," &lt;br/&gt;\n";
	}

	public static function __instance($a,$b,$c){
		if (!isset(self::$instance)){
			self::$instance = new self($a,$b,$c);
		}
		return self::$instance;
	}
}

class Product51{
	public function __construct(){
		echo "Product51 &lt;br/&gt;\n";
	}
}

class Product52{
	private static $instance;
	
	private function __construct($a,$b,$c){
		echo 'Product52 ',$a,$b,$c," &lt;br/&gt;\n";
	}

	public static function __instance($a,$b,$c){
		if (!isset(self::$instance)){
			self::$instance = new self($a,$b,$c);
		}
		return self::$instance;
	}
}

class Product5Factory{
	public static function factory($a=null,$b=null,$c=null){
		if($a&#038;&$b&#038;&$c)
			return Product52::__instance($a,$b,$c);
		return new Product51();
	}
}


$product1 = Factory::factory('Product1');
$product2 = Factory::factory('Product2',array('a','b','c'));
$product3 = Factory::factory('Product3',null,'__instance');
$product4 = Factory::factory('Product4',array('a','b','c'),'__instance');
$product51 = Factory::factory('Product5');
$product52 = Factory::factory('Product5',array('a','b','c'));
</code></pre>

<p>Сразу оговорюсь что можно было бы сэкономить время вызвав $name::$func() (в строке 19) без параметров, если бы интерпритатор php перед тем как выполнить скрипт не преобразовывал вызовы всех статичных методов в вызовы функций, такая фича появиться с выходом PHP5.3</p>

<p>Для того чтобы создать один раз экземпляр класса Product  этого кода, конечно очень много, но если постоянно приходиться создавать экземпляры классов имена которых динамичны, то это очень хороший подод.</p>
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2007/07/25/pattern_factory/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>CORE</title>
		<link>http://mabp.kiev.ua/2007/06/11/core/</link>
		<comments>http://mabp.kiev.ua/2007/06/11/core/#comments</comments>
		<pubDate>Mon, 11 Jun 2007 14:50:02 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Видео]]></category>
		<category><![CDATA[Голоса в голове]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[Стихи]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=159</guid>
		<description><![CDATA[Эта статья является демонстрацией примера приведенного в статье Registry У этой статьи есть продолжение Pattern: Registry Как и было условлено ранее, класс должен реализовывать паттерн Singleton, чтобы исключить возможность создания его копии. class CORE{ private $tools; private static $instance; final private function __construct(){ echo "CORE::__construct()\n"; } static function &#038; __instance(){ if (!isset(self::$instance)) self::$instance = new [...]]]></description>
			<content:encoded><![CDATA[<table style="background-color:#EDEFF0;width:100%;"><tbody><tr><th><img src="/wp-content/themes/inove/img/warning_yellow.png"/></th>
<th style="text-align: center;">Эта статья является демонстрацией примера приведенного в статье <a href="http://mabp.kiev.ua/2007/02/22/registry/" title="Registry">Registry</a></th></tr></tbody></table>

<table style="background-color:#EDEFF0;width:100%;"><tbody><tr><th><img src="/wp-content/themes/inove/img/warning_yellow.png"/></th>
<th style="text-align: center;">У этой статьи есть продолжение <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/" title="Pattern: Registry">Pattern: Registry</a></a></th></tr></tbody></table>

<p>Как и было условлено ранее, класс должен реализовывать <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a>, чтобы исключить возможность создания его копии.</p>
<span id="more-159"></span>
<pre><code class="php">
class CORE{

	private $tools;
	private static $instance;
	
	final private function __construct(){ 
		echo "CORE::__construct()\n";
	}
	
	static function &#038; __instance(){
		if (!isset(self::$instance))
			self::$instance = new self;
		return self::$instance;
	}

	function __clone(){
		trigger_error('Clone is not allowed.', E_USER_ERROR);
	}
}
</code></pre>


<p>Теперь создать объект напрямую оператором <span style="color:#0000ff;font-weight:bold;">new</span> не получиться, а клонирование вызовет ошибку уровня <span style="color:#000000;">E_USER_ERROR</span>.</p>
<p>Свойство <span style="color:#000000;font-weight:bold;">tools</span> будет хранить в себе ссылки на все управляемые объекты, а <span style="color:#000000;font-weight:bold;">instance</span> ссылку на само ядро. Добавим методы регистрации и разнрегистрации объектов в ядре.</p>

<pre><code class="php">
	static function &#038; register($tool, $name=''){
		if (is_string($tool) &#038;& !$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 &#038;& is_callable(array($name,"kill"))) 
			call_user_func(array($name,"kill"));
	}
</code></pre>

<p>Здесь метод register принимает первым параметром объект или название класса из которого этот объект можно создать, а вторым имя под которым его нужно будет сохранить.</p>
<p>Метод unregister принимает название объекта который нужно уничтожить и флаг для форсирования уничтожения объекта.</p>
<p>Помимо этого используються еще два метода: has и factory, has проверяет не зарегистрирован ли уже объект с таким именем, а factory создает объект если указано только его название.</p>

<pre><code class="php">
	static function has($name){
		$instance = self::__instance();
		
		if (isset($instance->tools[$name]))
			return true;
			
		return false;
	}
	
	static function &#038; factory($name){
	
		if (is_object($name))
			return $name;

		if (!class_exists($name) &#038;& 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!");
	}
</code></pre>



<p>Немного подробнее о методе factory: он пытается создать экземпляр класса, когда известно только имя этого класса. Если такой класс не найден, то метод передает управление функции __autoload. Затем снова проверяет, доступен ли класс. Если не доступен, то бросает exception, а если доступен, то пытается создать его либо непосредственно используя оператор new, либо как <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a> используя метод __instance. При этот метод __instance вызывается статично!</p>
<p>Помимо всего этого нужен еще один метод, для доступа ко всему тому, что было зарегистрировано.</p>

<pre><code class="php">
	static function &#038; extract($name){
		if (!self::has($name))
			self::factory($name);
		$instance = self::__instance();
		return $instance->tools[$name];
	}
</code></pre>

<p>И заканчивает описание класса деструктор, который будет уничтожать объекты в обратном порядке их регистрации:</p>

<pre><code class="php">
	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";
	}
</code></pre>

<p>Теперь приведу пример работы с этим классом:</p>

<pre><code class="php">
class B 
{
	private static $instance;
	
	final private function __construct(){ 
		echo "B::__construct()\n";
	}
	
	static function &#038; __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
********************/
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2007/06/11/core/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Registry</title>
		<link>http://mabp.kiev.ua/2007/02/22/registry/</link>
		<comments>http://mabp.kiev.ua/2007/02/22/registry/#comments</comments>
		<pubDate>Thu, 22 Feb 2007 14:54:20 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=166</guid>
		<description><![CDATA[Это теоритическая часть, практическую можно найти на странице CORE Ну я думаю стоит начать из далека... когда еще деревья были большими а колбаса вкусной...Нет это слишком рано ;) Начнем с того что паттерны в программировании были придуманы никак не для PHP, а для Smalltalk. Ну а к PHPони были притянуты "за уши", с появлением 5-ой [...]]]></description>
			<content:encoded><![CDATA[<table style="background-color:#EDEFF0;width:100%;"><tbody><tr><th><img src="/wp-content/themes/inove/img/warning_yellow.png"/></th>
<th style="text-align: center;">Это теоритическая часть, практическую можно найти на странице <a href="http://mabp.kiev.ua/2007/06/11/core/" title="CORE">CORE</a></a></th></tr></tbody></table>

<p>Ну я думаю стоит начать из далека... когда еще деревья были большими а колбаса вкусной...<br />Нет это слишком рано ;) Начнем с того что паттерны в программировании были придуманы никак не для <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a>, а для Smalltalk. Ну а к <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a>они были притянуты "за уши", с появлением 5-ой версии. </p>
<p>Идея <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерна Registry</a> состоит в том что проект (читай : сайт) содержит много разнообразных классов, например класс для работы с БД и шаблонизатор. А теперь появился класс User который должен работать с БД и передавать данные шаблонизатору. Значит он должен знать о функциях SELECT и ASSIGN двух других классов. Классы можно было бы наследовать и получить этот доступ но наследовать в PHP можно только один класс, да и если проект большой то стоит ли наследовать 150 разных классов?! Значит надо передавать экземпляры классов в функции которые их используют, или еще лучше в конструктор а там присвоить их свойствам. А зачем передавать(?!) можно сразу создать новый экземпляр прямо в конструкторе User'a, допустим, а если при создании конструкторам нужно передавать параметры? Или можно использовать <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a> для того чтобы не пересоздавать объект каждый раз но это не всегда удобно. Ну, а что если, например вы решите сменить шаблонизатор с XTemplate на Smarty и придется искать и реплейсить все названия класса.</p>
<span id="more-166"></span>
<p>И придумали умные программисты создавать один класс который бы знал о всех остальных, и раздавал кому нужно ссылки на них! При всем этом желательно чтоб еще никто не создал случайно второй экземпляр этого чудо класса поэтому в нем используют <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a> Еще неплохо было бы там использовать фабричные методы но мы это опустим... покрайней мере пока</p>

<p>Итак создадим класс A и скажем что напрямую его создать нельзя будет, но можно создать через функцию instance(), а также создадим статичный метод для регистрации некого объекта B о котором известно только что он создается напрямую через конструктор.</p>

<pre><code class="php">
class A{

	public $registry;
	private static $instance;
	
	private function __construct(){
		echo "A::__construct()\n";
	}
	
    static function &#038; instance(){
        if (!isset(self::$instance)){
            self::$instance = new self;
        }
        return self::$instance;
    }
    
    public static function register(&#038;$obj){
    	$instance =&#038; A::instance();
    	$instance->registry = $obj;
    }
    
	public function __destruct(){ 
		echo "A::__destruct()\n";
	}
}

class B {

	public function __construct(){
		echo "B::__construct()\n";
	}
	
	public function __destruct(){
		echo "B::__destruct()\n";
	}
}

A::instance();
A::register(new B);

//RESULT :
//A::__construct()
//B::__construct()
//A::__destruct()
//B::__destruct()
</code></pre>

<p>Создали, зарегистрировали, прикольно. Теперь обратите внимание на порядок следования деструкторов. Логично было ло бы, чтоб деструктор класса A вызывался ПОСЛЕ деструктора B для этого изменим несколько строк</p>

<pre><code class="php">
	public function __destruct(){
		$instance =&#038; A::instance();
    	$instance->registry = null;
		echo "A::__destruct()\n";
	}

//RESULT :
//A::__construct()
//B::__construct()
//B::__destruct()
//A::__destruct()
</code></pre>

<p>Теперь вроде бы все правильно деструкторы вызываются в правильной последовательности, но регистрация одного класса ничего не даст надо регистрировать много классов и следить чтобы их деструкторы вызывались в правильной последовательности</p>

<pre><code class="php">
class A{

	public $registry;
	private static $instance;
	
	private function __construct(){
		echo "A::__construct()\n";
	}
	
    static function &#038; instance(){
        if (!isset(self::$instance)){
            self::$instance = new self;
        }
        return self::$instance;
    }
    
    public static function register(&#038;$obj,$name){
    	$instance =&#038; A::instance();
    	$instance->registry[$name] =&#038; $obj;
    }
    
    public static function &#038; extract($name){
    	$instance =&#038; A::instance();
    	return $instance->registry[$name];
    }
    
    public static function unregister($name) {
    	unset($instance->registry[$name]);
    }
    
	public function __destruct(){
		echo "Вызван деструктор A\n";
		$instance =&#038; A::instance();
		foreach ($instance->registry as $name => &#038;$obj){
			echo "Вызван деструктор $name\n";
    		$obj = null;
		}
		echo "Объект разрушен   A\n";
	}
}

class B{

	public function __construct(){
		echo "B::__construct()\n";
	}
	
	public function __destruct(){
		echo "Объект разрушен   B\n";
	}
}

class C{

	public function __construct(){
		echo "C::__construct()\n";
	}
	
	public function __destruct(){
		unset($this->B);
		echo "Объект разрушен   C\n";
	}
}

A::instance();
A::register(new B,'B');
A::register(new C,'C');

//RESULT
//A::__construct()
//B::__construct()
//C::__construct()
//Вызван деструктор A
//Вызван деструктор B
//Объект разрушен   B
//Вызван деструктор C
//Объект разрушен   C
//Объект разрушен   A
</code></pre>

<p>
Однако на этом проблемы не заканчиваются. Случилось собственно то ради чего все это затевалось
В объекте класса C понадобилась информация об объекте класса B 
</p>

<pre><code class="php">
class C{

	public $B;
	
	public function __construct(){
		echo "C::__construct()\n";
		$this->B =&#038; A::extract('B');
	}
	
	public function setB(&#038;$B){
		$this->B =&#038; $B;
	}
	
	public function __destruct(){
		echo "Объект разрушен   C\n";
	}
}

A::instance();
A::register(new B,'B');
A::register(new C,'C');

// или переприсваисаем значение через seter
A::extract('C')->setB(A::extract('B'));

//RESULT :
//A::__construct()
//B::__construct()
//C::__construct()
//Вызван деструктор A
//Вызван деструктор B
//Объект разрушен   B
//Вызван деструктор C
//Объект разрушен   C
//Объект разрушен   A
</code></pre>

<p>Примерно так выглядело ядро, этого сайта, пока я не перешел на <a href="http://mabp.kiev.ua/tag/wordpress/">WordPress</a>, только немного сложнее - с добавлением фабричных методов.</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2007/02/22/registry/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>

