Шаблоны проектирования
Шаблоны - это способ описания оптимальных методов и хороших дизайнов проектирования. Они предоставляют универсальные пути решения общих проблем программирования.
Фабрика (Factory)
Шаблон Фабрика позволяет создавать объекты во время работы программы. Этот шаблон называется Фабрикой потому, что он отвечает за производство объекта. Параметризированная фабрика принимает в качестве аргумента имя класса, объект которого создается.
Пример #1 Параметризированный фабричный метод
<?php
class Example
{
// Параметризированный фабричный метод
public static function factory($type)
{
if (include_once 'Drivers/' . $type . '.php') {
$classname = 'Driver_' . $type;
return new $classname;
} else {
throw new Exception('Драйвер не найден');
}
}
}
?>
Определение этого метода в классе позволяет драйверам быть загруженными "на лету". В случае, если класс Example был бы классом абстрактного доступа к базе данных, то загрузка драйвера MySQL и SQLite может быть выполнена следующим образом:
<?php
// Загрузка драйвера MySQL
$mysql = Example::factory('MySQL');
// Загрузка драйвера SQLite
$sqlite = Example::factory('SQLite');
?>
Синглтон (Singleton)
Шаблон проектирования Синглтон применяется в тех ситуациях, когда нужно получить единственный экземпляр класса. Синглтон является одним из четырех("Gang of Four") основных создающих шаблонов.
Синглтон обычно применяется в классах для баз данных, логирования, контроллеров(Front Controller) и объектах, определяющих запросы и ответы(Request и Response).
Пример #2 Пример Синглтона
<?php
class Example
{
private static $instance;
private $count = 0;
private function __construct()
{
}
public static function singleton()
{
if (!isset(self::$instance)) {
echo 'Создание нового экземпляра.';
$className = __CLASS__;
self::$instance = new $className;
}
return self::$instance;
}
public function increment()
{
return $this->count++;
}
public function __clone()
{
trigger_error('Клонирование запрещено.', E_USER_ERROR);
}
public function __wakeup()
{
trigger_error('Десериализация запрещена.', E_USER_ERROR);
}
?>
Пример ниже иллюстрирует использование Синглтона
<?php
$singleton = Example::singleton(); // выведет "Создание нового экземпляра."
echo $singleton->increment(); // 0
echo $singleton->increment(); // 1
$singleton = Example::singleton(); // вернет тот же самый экземпляр
echo $singleton->increment(); // 2
echo $singleton->increment(); // 3
// все строки ниже вызывают неисправимую ошибку
$singleton2 = new Example;
$singleton3 = clone $singleton;
$singleton4 = unserialize(serialize($singleton));
?>
Паттерн Синглтон является одним из наиболее противоречивых паттернов. Критики утверждают, что Синглтоны вводят глобальные состояния при их применении и тесно связывают Синглтон и использующие его классы. Это приводит к скрытой зависимости и неожиданным побочным эффектам, что в свою очередь приводит к коду, который сложнее тестировать и поддерживать.
Критики также утверждаю, что не имеет смысла использовать Синглтон в архитектурах "ничего общего" (Shared Nothing Architecture), таких как PHP, где объекты являются уникальными в пределах запроса и никак иначе. Проще и аккуратнее создавать структуры взаимосвязанных объектов с помощью шаблонов Строителей(Builders) и Фабрики(Factory) за один раз в начале запроса.
Синглтоны также нарушают некоторые из "Жестких" принципов ООП проектирования и Закон Деметры. Синглтоны нельзя сериализовывать. Они не могут быть подклассами (до PHP 5.3) и не будут собираться сборщиком мусора из-за того, что экземпляр хранится в статическом атрибуте Синглтона.
- Введение
- Основы
- Свойства
- Константы классов
- Автоматическая загрузка классов
- Конструкторы и деструкторы
- Область видимости
- Наследование
- Оператор разрешения области видимости (::)
- Ключевое слово "static"
- Абстрактные классы
- Интерфейсы объектов
- Трейты
- Anonymous classes
- Перегрузка
- Итераторы объектов
- Магические методы
- Ключевое слово "final"
- Клонирование объектов
- Сравнение объектов
- Контроль типа
- Позднее статическое связывание
- Объекты и ссылки
- Сериализация объектов
- Журнал изменений ООП
Коментарии
I struggled a few hours on writing a simple Generic factory method for dynamic object factoring. I initially went for call_user_func_array() to create the object but that obviously didn't work. An anonymous function was what I needed. Here's the result (PHP5):
<?php
/**
* Name: Factory
* Author: Ezku
* Contact: dmnEe0 at gmail dot com
*/
class Factory
{
/**
* Generic factory method
* @param string Path to class definition
* @param string Basic class name
* @param string Derived class name
* @param array Class constructor arguments, optional
*/
public static function Generic($filename, $base, $derived, $args = array())
{
/**
* Check that the file exists
*/
if(file_exists($filename))
{
include_once $filename;
/**
* Check that the file contained the appropriate class definition
*/
if(class_exists($derived))
{
/**
* Create argument list for constructor
*/
$arglist = array();
for($i = 0, $n = count($args); $i < $n; $i++)
$arglist[] = '$args['.$i.']';
$arglist = implode(',',$arglist);
/**
* Create new instance via an anonymous function
*/
$new_class = create_function('$name, $args', 'return new $name('.$arglist.');');
return $new_class($derived, $args);
}
else
throw new Exception("Definition file ($filename) did not contain definition for the $base class <code>$derived</code>");
}
else
throw new Exception("Definition file ($filename) for the $base class <code>$derived</code> was not found");
}
}
/**
* Useless usage example:
*/
function createCat($name, $scary_eyes = FALSE, $whiskers = TRUE)
{
$path = PATH_ANIMALS.'/'.$name.'.php';
$base = 'Cat';
$derived = $name.$base;
$args = array($scary_eyes, $whiskers);
return Factory::Generic($path, $base, $derived, $args);
}
// Create a MeowCat with scary eyes and whiskers
$cat = createCat('Meow', TRUE);
// Do whatever
?>
After programming a number of real world applications with PHP, I found that this version of the singleton doesn't really resemble other singleton patterns, but is the only one I've ended up using and it works great.
<?php
class User {
/* .. your code, nothing specific matters in the class .. */
}
function user(){
static $user;
if(!isset($user))
$user = new User();
return $user;
}
//creates the user object then calls a method on it
user()->doSomething();
//calls a method on the same object
user()->doSomethingElse();
?>
Note that it is *possible* to create multiple instances of User, but in your API docs, or when you tell people how to use the class just say you are supposed to refer to it only via the user() function, and then there should be no reason to enforce it in your code any other way.
Also note that this syntax is only possible in PHP 5 because of the object / function dereferencing feature. user()->someMethod(); will throw a fatal error in 4.x
Here's an effective strategy for creating singletons.
1.) define an __autoload() function
2.) Define all properties of a class to be static
3.) Make the constructor private.
Now, anywhere in your code, you can simply do as follows:
Class::Function();
The __autoload() function will take care of loading the class.
It's even better when you use the auto_prepend directive to define __autoload(). Now you can create a php script which looks like this:
<?php
TemplateSystem::Start();
echo 'This is just a test!';
TemplateSystem::Stop();
?>
Now you've effectively got a 2-line solution to all templating issues, the templates will be available to every script, and the only additional overhead that you'll have for scripts that don't use the templating system is a 3-line autoload function!
Obviously, there's still a problem with __autoload() if you are attempting to write a templating system that has to work with someone else's software that also defines __autoload(). The best advice I can give here is to remove one of the __autoload()'s and modify the other to work with both.
Please use design patterns as they were intended:
Design patterns are designs that are known to solve common problems, such as having only 1 instance of a class. Design patterns are are not code libraries.
Most design patterns, if not all, have alternate implementations but common to them all is that the recommended implementation solves the problem.
Singleton should not be made as a class and then extended. Nor shuld __autoload be used.
Autoloading is very PHP-specific (and there might be nothing wrong with that, but design patterns are general patterns that are abstracted from the implementing language).
Making a class that you extend is very ugly. What if you have to extend that class too? You will have to make a dummy that extends your singleton class, just so you can extend the class you want. This is a very "ugly" solution that completely overrules the idea of well known design patters: A thought-though idea that works the way intended.
The manual shows a PHP implementation of the standard Singleton-pattern without "nifty" modifications.
To finish off this lesson on design patterns, I would like to ackknowledge that there is nothing wrong in tweaking patterns to suit your needs.
But remember: "If it isn't broken - don't fix it".
Hi ,
Singleton Patterns are excellent ,
I have created a singleton pattern that enables any class to be loaded from the one modular singleton library.
<?php
class singleton
{
private static $o_instance = NULL ;
public static function call_singleton ( $s_class )
{
if ( class_exists ( $s_class ) )
{
if ( self :: $o_instance === NULL )
{
self :: $o_instance = new $s_class ;
}
}
return self :: $o_instance ;
}
}
?>
If you need singleton of any class and don't want write singleton wrapper for each this class, try this:
<?php
class UniverzalSingleton {
const EXCEPTION_NO_CLASS = 1;
protected static $_instances = array();
public static function getInstance($class) {
if (!isset(self::$_instances[$class])) {
if (!class_exists($class))
throw (new Exception(__CLASS__ . ': Requsted class is not exist.', self::EXCEPTION_NO_CLASS));
self::$_instances[$class] = new $class();
} // if
return self::$_instances[$class];
} // getInstance
} // class UniverzalSingleton
?>
Short version of Singleton:
<?php
public function __clone()
{
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
?>
is :
<?php private function __clone() {} ?>
Regarding the singleton pattern, you have to create the function for every singleton class you want to have, because settting a variable static will set the variable on all instances of the class, and second of all, by extending a singleton class, you are breaking rule No #1 of the singleton pattern. an instance of a given type may only excist ONCE, by extending the singleton class you have multiple instances of the singleton class, and by is sharing the static $instance variable.
on thing could be done though, to make sure a programmer does not make any mistakes when creating singleton classes, an interface could be made, to make sure the singleton class is correctly defined.
it could look something like this:
<?php
interface singleton {
public static function getInstance();
}
?>
however, this interface does NOT force the programmer to make the constructor private, and don't even bother to try, it would just result in a error.
sorry to say it guys, there are no easy way around this one. not even a factory class can do the job for you since, the constructor must be private, to ensure that only one instance excists.
The principle of the Singleton pattern can easily be expanded to form [what I have dubbed as] the 'Unique' pattern - where a particular class may have several instances, each with a 'Unique ID'. This can be useful when a single instance is required for each database record.
<?php
// Each instance of 'Customer' represents one customer!
class Customer {
// Access a unique instance of class for a customer record
public function Unique($CustomerID) {
static $instances = array();
// a unique instance for each CustomerID
if(!isset($instances[$CustomerID]))
$instances[$CustomerID] = new Customer($CustomerID);
return $instances[$CustomerID];
}
private $CustomerID;
private function __construct($CustomerID) {
$this->CustomerID = $CustomerID;
}
}
// get instance of class for customer #1
$C1 = Customer::Unique(1);
// get instance of class for customer #2
$C2 = Customer::Unique(2);
?>
Singleton is a very useful pattern if you need multiple instances of different classes to use only one unique instance of common class. It's not just about having static methods.
e.g. Your database connection class probably should be a singleton, in order to spare all redundant connect calls, etc...
I don't agree to take a class with only static members and static methods as a 'singleton'. According to GoF's book, the singleton pattern means a class that only have one instance. A class containing only static members and functions still can be instantiated and extended, it have multiple instances. Consider the code below:
<?php
class StaticTest
{
private static $_test = "aaa";
public static function test()
{
echo self::$_test;
}
}
$obj = new StaticTest();
?>
The code will not report errors(although it's useless). So there can be many instances of the class.
It's reasonable that there is a class that create and store a unique instance of another class. Such as:
<?php
class A
{
private $_id = 0;
public function getId()
{
return $this->_id;
}
}
class B
{
private static $_instance;
public static function singleton()
{
if (!isset(self::$_instance)) {
self::$instance = new A();
}
return self::$instance;
}
}
?>
Here class B act as a guard to class A. But as same as the first section, it's useless too! Unless you can make sure that the users of your class will never find the class A, you shouldn't make the class you wanna to be unique can be instantiated many times.
So the best way to create a unique instance of a class is that the class save the unique instance itself. It is the core meaning of singleton pattern. Any information that mentioned here can be found in the book of GoF. I think it's worth reading the book.
BTW: It's allowed that there are a few of subclasses of a singleton class.
It's often forgotten, but a singleton class MUST be final. So it's useless to have a base class that implements the pattern and to inherit of it. That's why it's called a pattern and not a class library.
Here a little example that will show why.
<?php
class A {
// singleton pattern with getInstance static method
private $var; // A ressource variable
function __construct() {
$this->var = "get a ressource that could only be taken one time by process";
}
}
class B extends A {
// singleton pattern
function __construct() {
parent::__construct();
}
}
$anA = A :: getInstance();
$aB = B :: getInstance(); // try to get a second ressource, :(
?>
When developping class A, you may have think to be the only one with a $var ressource, but it's completly wrong. As $aB is an A (Think that there is two A instanciate and one with more than just A), $anA and $aB will have a different ressource variable and thus two different database connection for eg.
You'd never know how will be used your code, so you need to make it strong. This is the way of poo thinking.
An easy way to have your singleton persistent between page loads:
<?php
/**
* Returns an instance of the singleton class.
* @return object The singleton instance
*/
public static function _instance()
{
// Start a session if not already started
Session::start();
if ( false == isset( $_SESSION[ self::$_singleton_class ] ) )
{
$class = self::$_singleton_class;
$_SESSION[ self::$_singleton_class ] = new $class;
}
return $_SESSION[ self::$_singleton_class ];
}
/**
* Destroy the singleton object. Deleting the session variable in the
* destructor does not make sense since the destructor is called every
* time the script ends.
*/
public static function _destroy()
{
$_SESSION[ self::$_singleton_class ] = null;
}
/**
* Initialize the singleton object. Use instead of constructor.
*/
public function _initialize( $name )
{
// Something...
}
/**
* Prevent cloning of singleton.
*/
private function __clone()
{
trigger_error( "Cloning a singleton object is not allowed.", E_USER_ERROR );
}
private static $_singleton_class = __CLASS__;
?>
It's sometimes useful to let one sigleton class extend another. You can achieve this by only using static attributes:
<?php
class A {
private static $value = 0;
private static $instance = null;
private function __construct() {
$this->set(time());
}
public static function getInstance() {
if (is_null((self::$instance))) {
$class_name = __CLASS__;
self::$instance = new $class_name;
}
return self::$instance;
}
private function set($i) {
self::$value = $i;
$this->out();
}
public function out() {
echo self::$value;
}
}
class B extends A {
public static $instance = null;
public static function getInstance() {
parent::getInstance();
if (is_null(self::$instance)) {
$class = __CLASS__;
self::$instance = new $class;
}
return self::$instance;
}
}
$b = B::getInstance();
$b->out();
?>
This will output the current time twice. If $value isn't static, the call to $b->out() will output 0. Maybe it can save someone some time...
A pure extendable(multiple sublevels) Singleton class in PHP seems impossible at the moment because of the way PHP handles static inheritance, but my class is close to what i want.
Very simple usage:
<?php
class Test extends Singleton {
public static function getInstance(){
return Singleton::getSingleton(get_class());
}
}
?>
Singleton class implementation:
<?php
class Singleton {
/***********************
* HOW TO USE
*
* Inherit(extend) from Singleton and add getter:
*
* //public getter for singleton instance
* public static function getInstance(){
* return Singleton::getSingleton(get_class());
* }
*
*/
private static $instanceMap = array();
//protected getter for singleton instances
protected static function getSingleton($className){
if(!isset(self::$instanceMap[$className])){
$object = new $className;
//Make sure this object inherit from Singleton
if($object instanceof Singleton){
self::$instanceMap[$className] = $object;
}
else{
throw SingletonException("Class '$className' do not inherit from Singleton!");
}
}
return self::$instanceMap[$className];
}
//protected constructor to prevent outside instantiation
protected function __construct(){
}
//denie cloning of singleton objects
public final function __clone(){
trigger_error('It is impossible to clone singleton', E_USER_ERROR);
}
}
?>
Just a simple test case:
<?php
class A extends Singleton {
protected $rndId;
protected function __construct(){
$this->rndId = rand();
}
public function whatAmI(){
echo 'I am a A('.$this->rndId.')<br />';
}
public static function getInstance(){
return Singleton::getSingleton(get_class());
}
}
class B extends A {
public function whatAmI(){
echo 'I am a B('.$this->rndId.')<br />';
}
public static function getInstance(){
return Singleton::getSingleton(get_class());
}
}
$a = A::getInstance();
$b = B::getInstance();
$a->whatAmI();// should echo 'I am a A(some number)
$b->whatAmI();// should echo 'I am a B(some number)
$a = A::getInstance();
$b = B::getInstance();
$a->whatAmI();// should echo 'I am a A(same number as above)
$b->whatAmI();// should echo 'I am a B(same number as above)
$a = new A();// this should fail
$b = new B();// this should fail
?>
I hope this helps.
-Eyvind-
Here's a way to make singleton classes with no extra code other than "extends Singleton" - if you use __AutoLoad() and keep each class in a separate file that is...
<?php
abstract class Singleton {
// Cannot be instantiated by any other class
protected function __Construct() { }
// Cannot be cloned ever
private function __Clone() { }
// Create/fetch an instance of the class
static public function getInstance($ClassName = null) {
static $Instance;
if ($Instance) {
return $Instance;
} elseif ($ClassName) {
$Instance = new $ClassName;
return $Instance;
} else {
return null; // or throw exception if you want...
}
}
}
function __AutoLoad($ClassName) {
include "$ClassName.php";
if (is_subclass_of($ClassName, 'Singleton')) {
eval($ClassName.'::getInstance($ClassName);');
}
}
// ClassName.php
class ClassName extends Singleton {
// ... Code ...
}
// To use
$a = ClassName::getInstance();
$a->MyFunc();
?>
Of course you could do this differently - the point is that you can use __AutoLoad() to tell the single what class it is, unlike some other ways where this is done manually every time you define a singleton class.
This's a example of Composite Pattern:
<?php
abstract class Graphic{
abstract public function draw();
}
class Triangle extends Graphic{
private $name = '';
public function __construct($name = 'unknown'){
$this->name = $name;
}
public function draw(){
echo '-I\'m a triangle '.$this->name.'.<br>';
}
}
class Container extends Graphic{
private $name = '';
private $container = array();
public function __construct($name = 'unknown'){
$this->name = $name;
}
public function draw(){
echo 'I\'m a container '.$this->name.'.<br>';
foreach($this->container as $graphic)
$graphic->draw();
}
public function add(Graphic $graphic){
$this->container[] = $graphic;
}
public function del(Graphic $graphic){
unset($this->container[$graphic]);
}
}
$tri1 = new Triangle('1');
$tri2 = new Triangle('2');
$tri3 = new Triangle('3');
$container1 = new Container('1');
$container2 = new Container('2');
$container3 = new Container('3');
$container1->add($tri1);
$container1->add($tri2);
$container2->add($tri3);
$container3->add($container1);
$container3->add($container2);
$container3->draw();
?>
The above example will output:
I'm a container 3.
I'm a container 1.
-I'm a triangle 1.
-I'm a triangle 2.
I'm a container 2.
-I'm a triangle 3.
Dario Ocles.
Simplest PHP5 singleton implementation ever:
<?php
class Some_Class
{
static private $_i;
private function __construct()
{
}
static public function singleton() {
return isset(self::$_i) ? self::$_i : self::$_i = new self();
}
}
?>
This allows for singleton functionality via class extension, and does not use any shady functions like eval.
<?php
interface ISingleton {
public static function GetInstance();
}
class Singleton implements ISingleton {
public static function GetInstance($class='Singleton') {
static $instances = array();
if (!is_string($class)) {
return null;
}
if ($instances[$class] === null) {
$instances[$class] = new $class;
}
return $instances[$class];
}
}
class Mars extends Singleton implements ISingleton {
public static function GetInstance() {
return Singleton::GetInstance(get_class());
}
}
class Neptune extends Singleton implements ISingleton {
public static function GetInstance() {
return Singleton::GetInstance(get_class());
}
}
$x = Mars::GetInstance();
echo '<pre>'.print_r($x,true).'</pre>';
$x = Neptune::GetInstance();
echo '<pre>'.print_r($x,true).'</pre>';
?>
If you want a singleton and you don't mind on throwing a stop error/exception when a 2nd instace is created instead of returning the already created object, then this code works with subclassing and without getInstace alike functions (just with __construct)
<?php
class SINGLETON
{
// the array for checking the created instances
protected static $singletons = array ();
// make it final so extended classes cannot override it
final public function __construct ()
{
$classname = get_class ( $this );
if ( ! isset ( self::$singletons[$classname] ) )
// instead of $this it could be any value since we are checking for isset, but a reference to the object may be useful in a possible improvement, somewhat
self::$singletons[$classname] = $this;
else
// your favorite stop error here
trow new Exception ();
}
// final as well, no overriding, plus protected so it cannot be called
final protected function __clone () {}
}
class X extends SINGLETON
{
//...
}
class Y extends X
{
//...
}
$x = new X ();
$y = new Y ();
$a = new X (); // execution stops, as an instance of X is created already
$b = new Y (); // execution stops, as an instance of Y is created already, it DOES NOT give problems with X, despite extending X
?>
so, if it is ok to stops the execution, this method is way simpler
it must stops the execution because no matter what, __construct will return a reference to the new object, always, so if the script goes on further you will have effectively 2 instances (as a matter of fact, the code above only checks the existence of another object from the same class, it does not prohibit the creation of a new one)
hth
A tricky way to implement Factory or Singleton is this one:
<?php
class A {
// your amazing stuff
}
// implicit factory
function A( /* one or more args */ ){
return new A( /* one or more args */ );
}
$a = A(1,2,3);
$b = A(2,3);
// or implicit Singleton
function A( /* one or more args */ ){
static $instance;
return isset($instance) ? $instance : ($instance = new A( /* one or more args */ ));
}
A(1,2,3) === A(2,3); // true
?>
More details in WebReflection, byez
Db layer design algorithm:
"Separation of database layer by database functionality"
First we draw this line:
Application
-------------
DB
Here comes the new thing:
The db layer we separate it into two areas like this:
Db layer
|
select | insert, update delete
|
in the left side we have the select part.
The difference between the left and the right sides is that select side has no connection with the db structure - you can take data querying all table, while the right side is table oriented.
Select side:
Here all queries are in one file called "getters". Like getterUsers.
Inside it will be the body of the query but the fields that are to be selected will be build dynamically.
When calling this "getter" you will provide an array of fields to be selected or no fields, situation when it will take all fields.
To keep those db field names as low as possible in this architecture - so the above code dont need to know about the name of the fields in db, you will make just above this "getter", a "filter" file.
This filter will have a switch with a key and inside will call the getter with fields from db.
Ex:
<?php
switch(key)
case 'Label':
$fields = array("label", "firstName");
$obj->getUser($fields)
break;
?>
Above this filter you will have a "caller" that will call the "filter" with the key:
Ex:
<?php
function callerUserLabel()
{
->filterUserLabel('Label');
}
?>
So in the higher code you just make
->callerUserLabel();
and this will return all what you need.
If you want this query to get out of the db and another field called "email", you just create another case in the switch and a "caller" to call that case.
Dynamic and extensible.
----------------
Now on the insert update side.
Here we only think in db tables.
First we do some "checkers" for all fields in db.
checkerTableName.php
This will contain an array with all the fields and the checks that must be done on that field and perform the checks only on the provided fields.
Then we do the "updaters". Those are build dinamically like the "getters" - if fields provided, only those updated. If all fields provided, can be used as an "inserter".
When performing an insert, all checks on that table will be done.
When performing an update on only one field - like updating a label, only that label will be checked to be in conformity with requirements like a length, special chars inside.
Dependency checks are made here also.
When having in one application action a multiple insert or update (when inserting an operator also add a webUser lets say) you do above those "inserter" and "updater" files a small "manager" that will do:
->checkOperatorFields();
->checkWebUserFields();
->insertOperator();
->insertWebUser();
If no error is thrown, all things will go nice and quiet.
Now also the "getters" will have their fields checked when needed using those checkers. I am talking about the values that are given as parameters not about the ones that are returned from db.
If you are working with domain objects or business logic objects (whatever you call them) above the db layer you will have to make below that line we first draw a "business logic asambler" object that will make from your data what you want.
If this dont exist, at least an intermediary layer that will map the names from db with the ones used in application must be done in both directions - from application to db and from db to application.
-------------------------------------
Advantages of this architecture:
- Usefull in complex application especheally where the selects are made ussually from many tables so you dont have to load lots and lots of files and to get lost in the logic for one simple select.
- NO DUPLICATE CODE
- Simple and intuitive.
- Flexible and expendable.
For quick instance access use function
<?php
class Example{....}
function Example {
return Example::getInstance();
}
// Global access
Example()->sayHallo(...);
Example()->doSomething(...);
print Example()->someData;
?>
I've been forward-developing for PHP 5.3, and couldn't help but notice that late-static-binding makes implementing Singletons simple. Its even easy to set up some function forwarding so that static calls are transformed into non-staic calls:
<?php
// Requires PHP 5.3!
class Singleton {
public static function Instance() {
static $instances = array();
$class = get_called_class();
if (!array_key_exists($class, $instances)) {
$instances[$class] = new $class();
}
return $instances[$class];
}
public static function __callStatic($func, $args) {
$class = static::Instance();
return call_user_func_array(array($class, '__'.$func), $args);
}
}
class Earth extends Singleton {
public function __DoSomething($a, $b) {
return 15 + $this->SomethingElse($a, $b);
}
protected function SomethingElse($c, $d) {
return $c % $d;
}
}
echo Earth::DoSomething(6,27);
?>
The singleton effect you are applying to can be achieved in a old-fashioned and simpler way. Remember that the 'static' is the way for sharing the data between the objects from one type. And there is no pattern in this. So the only think you can do is to use the static keyword. If your program is already written and the rewrite is not recommended there is the "adapter pattern" witch can be used. It is intended to adapt an object to an already build environment. This is one way to have singleton functionality without actually the singleton pattern, it uses a class with static data and static methods and a adaptor class to adapt those methods to your interface.
The example shows how the every instance of the singlePoint class givs you the same data.
<?php
class single {
static $a;
static $b;
protected static function _start($a,$b){
self::$a=$a;
self::$b=$b;
}
protected static function _get_a(){
return self::$a;
}
protected static function _get_b(){
return self::$b;
}
}
class singlePoint extends single {
public function __construct($a='',$b=''){
if($a!='' && $b!=''){
single::_start($a,$b);
}
}
public function get_a(){
return single::_get_a();
}
public function get_b(){
return single::_get_b();
}
}
class scopeTest{
public function __construct(){
$singlePointInstance = new singlePoint();
echo 'In scopeTest a='.$singlePointInstance->get_a().'<br />';
}
}
$theSingle = new singlePoint(3,5);
echo 'In index a='.$theSingle->get_a().'<br />';
$theScopeTest = new scopeTest();
?>
My point is that you don't need single instance of the class but you need access to the same data over and over again ant the build in way to do that in every language I know so far is the 'static' keyword. It was engineered to give you this functionality. All the singleton patterns and even this adapter is unnecessary complication of the structure. KISS = “Keep It Simple Stupid” no need of that!
Let me describe another pattern it is called “Decorator”. It can be used to add features to already written object. It is useful for extending some library classes from your framework without changing the original classes (especially if somebody else wrote those). The actual meaning is best presented in an example.
<?php
// the main interface in which we going to do some decoration
interface salad{
public function wait();
}
// main class which is already defined and you can't or don't want to change
class shopSalad implements salad{
private $tomatoes;
private $cucumbers;
private $cheese;
public function __construct($tomatoes, $cucumbers, $cheese){
$this->tomatoes = $tomatoes;
$this->cucumbers = $cucumbers;
$this->cheese = $cheese;
}
public function wait(){
echo "the salad is served using {$this->tomatoes} tomatoes, {$this->cucumbers} cucumbers and {$this->cheese} gr. of cheese.";
}
}
// abstract decorator class - note that it implements salad
abstract class saladDecorator implements salad{
protected $salad; // the object for decoration
public function __construct(salad $salad){
$this->salad=$salad;
}
// there is no need to mention the wait function therefore this class inherits the original salad
// the purpose of this class is maintaining the type of the object produced by the decorators.
// it inherits the same interface as the original and it will be inherited by the concrete decorators
}
// sauce decorator
class saladSauce extends saladDecorator {
public function wait(){
$this->salad->wait();
echo " Then it was decorated with some sauce.";
}
}
// onions decorator
class saladOnions extends saladDecorator {
public function wait(){
$this->salad->wait();
echo " Then it was decorated with some onions.";
}
}
$order1 = new shopSalad(2,1,100); // creates the salad in the normal way
$order1 = new saladSauce($order1); // add a decorator to the class
$order1->wait();
echo '<br />';
// or
$order3 = new saladOnions(new saladSauce(new shopSalad(1,0.5,50))); // you don't need to load a variable with the reference
$order3->wait();
?>
this will outputs:
the salad is served using 2 tomatoes, 1 cucumbers and 100 gr. of cheese. Then it was decorated with some sauce.
the salad is served using 3 tomatoes, 2 cucumbers and 100 gr. of cheese. Then it was decorated with some onions. Then it was decorated with some sauce.
the salad is served using 1 tomatoes, 0.5 cucumbers and 50 gr. of cheese. Then it was decorated with some souse. Then it was decorated with some onions.
The pattern is not intended to be used with simple object and I couldn't do more simple than that. The pattern is useful in every way when the extending of an object is required. It can be used to divide some methods from others or to create layers of interaction with the object. In example if you have an file interface and a imageFile class which implements the file and then you can have also an textFile for the textFile you can do some layering and if you want to read the file as XML you can mace a decorator to do so. The XML decorator will inherit the interface file so you can save it and the instance of textFile will be given to create the decorator so you can read the actual text and pars it as XML. It is possible the file to be .ini or some other text based document and you can make a decorator for every one of them. This is the actual benefit of the pattern.
Till now writing singleton classes depends on making class constructor private or protected and that sounds good, but what if class constructor must be public (for example, a singleton class inherits from a non-singleton class which already has a public constructor). The way to do so is:
<?php
class nonSingleton
{
protected $_foo;
public function __construct($foo)
{
$this -> _foo = $foo;
}
}
class Singleton extends nonSingleton
{
/**
* Single instance of the class
*
* @var Singleton
*/
protected static $_instance = NULL;
/**
* A flag to know if we are in getInstance method or not.
*
* @var bool
*/
protected static $_withinGetInstance = false;
/**
* Public singleton class constructor
*
* @param mixed $foo
*/
public function __construct($foo)
{
if (! self :: $_withinGetInstance)
throw new Exception('You cannot make a new instance of this class by using constructor, use getInstance() instead...');
parent :: __construct($foo);
/*
Any other operations constructor should do...
*/
}
/**
* Regular getInstance method
*
* @param mixed $foo
* @return Singleton
*/
public static function getInstance($foo)
{
self :: $_withinGetInstance = true;
if (! self :: $_instance)
self :: $_instance = new Singleton($foo);
self :: $_withinGetInstance = false;
return self :: $_instance;
}
}
?>
1: The singleton pattern ensures that only one instance of a class is ever created. Thus, applying it to a database connection object is common, since reusing a connection reduces latency and slows down reaching the database server's connection limit. If a database connection is only made in the singleton's constructor then it is probably impossible to accidentally open another connection via that object.
I say "probably impossible" because there are still some other issues: in this example, an invalid database connection identifier can be stored, retrieved, or lost (since it is an unserializable resource type) via object serialization without careful attention to the __sleep and __wakeup magic methods (and probably won't be valid on deserialization even if it is retained), and the __clone magic method should be implemented in a way that prevents object duplication.
(This example also ignores database connection pooling to stay focused on singletons.)
2: A singleton does not contain itself; it contains a reference to itself, which is conceptually similar to a pointer from the C language or a reference from Java. (In fact these are all very different under the hood and in practice, but I will ignore this for simplicity.)
Consider the following typical PHP 5.0 to 5.2 implementation:
<?php
class Example {
private static $instance;
private __construct() {
// Do important initializations here, like normal.
}
public static function getInstance() {
if (null == self::$instance):
// First invocation only.
$className = __CLASS__;
self::$instance = new $className();
endif;
return self::$instance;
}
public function __clone() {
throw new Exception('Illegally attempted to clone ' . __CLASS__);
}
}
?>
Static class member variables can exist even without an instance of their class, and static class methods can be invoked without a class instance as well. The member variable that holds a reference to the singleton class instance ($instance) is static, as is the method to instantiate a singleton object (Example::getInstance()). Note that the variable $instance is private, so it cannot be affected by anything external to the class (thus preventing outside code from creating an instance of Example).
Static member variables are not really "inside" a class; each class instance points to the same static member variables as other instances, "sharing" these static variables between them (in a way) even before any class instances exist. Thus, Example::getInstance() always checks the same $instance variable.
3: The constructor has an access specifier of "private" to prevent direct instantiation using the "new" operator. (Prior to the implementation of the __callStatic features of PHP 5.3 it is not useful to mark the constructor "protected" since subclasses won't automatically also be singletons.) However, private methods can be invoked from a class's other methods; the static method Example::getInstance() is therefore allowed to invoke the private constructor. On first invocation, it creates an instance of Example and stores a reference to it in $instance. Subsequently, it just returns this reference.
4: The singleton pattern makes a class (slightly) more complicated, and the overhead of invoking its instantiation method is probably slightly higher than accessing a global variable instead. However, the benefits are substantial from an architectural perspective: it helps prevent performance losses due to accidentally instantiating more than one heavyweight class, it helps prevent bugs due to accidentally instantiating more than one instance of a class (such as a class that renders the requested HTML document in an online content management system), and helps keeps your global namespace and other lexical scopes clean even prior to the introduction of proper namespaces in PHP 5.3 (thus helping to prevent accidental variable clobbering or unexpected initial variable values from a previous module).
Hello! I want to suggest another fast and universal way to create a singleton, that can store instances any class types. The idea based on php's ability to create object's properties in run time, and magic functions support. Main trick is to create not existed property in __get method and assign to it a value of new instance of class, named as property.
Code:
<?php
class fClassOne
{
public function get()
{
return "value 1<br>\n";
}
public function __construct()
{
echo "fClassOne constructed<br>\n";
}
}
class fClassTwo
{
public function get()
{
return "value 2<br>\n";
}
public function __construct()
{
echo "fClassTwo constructed<br>\n";
}
}
class fSingleton
{
public function __get($sClassName)
{
echo "isset check<br>\n";
if(!isset($this->{$sClassName})) $this->{$sClassName} = new $sClassName;
return $this->{$sClassName};
}
}
$MySingleton = new fSingleton();
for ($i = 0; $i < 5; $i++) echo $MySingleton->fClassOne->get();
echo $MySingleton->fClassTwo->get();
echo $MySingleton->fClassTwo->get();
?>
Output:
isset check
fClassOne constructed
value 1
value 1
value 1
value 1
value 1
isset check
fClassTwo constructed
value 2
value 2
I think a simpler option is to have a loader class/object and then the actual class. It keeps your class more secure in that you are defining the visibility on $instances and you keep your class neat and tidy.
I found this useful when trying to use the singleton method on a class that extends another class.
<?php
class module_loader {
private static $instances;
public static function getInstance($module_name) {
if (!isset(self::$instances[$module_name])) {
self::$instances[$module_name] = new $module_name();
}
return self::$instances[$module_name];
}
}
class module_base {
proteced $name;
public function __construct() {
// Do initialization stuff here
}
public final function SomePermanentFunction() {
// Perform function actions
}
}
class module_test extends module_base {
public $my_var;
public function __construct() {
parent::__construct();
$this->name = 'test';
$this->my_var = '';
}
public function ModuleSpecificFunction() {
}
}
?>
So then once you have all of that defined, you can then use it like such:
<?php
// Get first instance and set value
$instance1 = module_loader::getInstance('module_test');
$instance1->my_var = 'abc';
print "Instance 1 Var = " . $instance1->my_var;
// Create second instance and check value
$instance2 = module_loader::getInstance('module_test');
print "Instance 2 Var = " . $instance2->my_var;
// Set value on second instance, check first instance
$instance2->my_var = 'def';
print "Instance 1 Var = " . $instance1->my_var;
?>
The output would then look like this:
Instance 1 Var = abc
Instance 2 Var = abc
Instance 1 Var = def
Thus $instance1 and $instance2 are created using the factory pattern but they both point back to the same object (singleton pattern).
Exemple of singleton that can be used for other class (need phpversion >= 5.3)
<?php
class SingletonModel
{
/**
* Instance of singleton's class
*
* @var array
*/
private static $_instance;
/**
* All constructeur should be protected
*/
protected function __construct(){}
/**
* Singleton method to load a new object
*
* @return HlPwd_SingletonModel
*/
public static function singleton()
{
if (!isset(self::$instance[ get_called_class() ]))
{
$c = get_called_class();
self::$instance = new $c;
}
return self::$instance;
}
/**
* Destroy the singleton
*/
public function destroySingleton()
{
unset(self::$_instance[ get_class($this) ]);
}
/**
* Destructeur
*/
public function __destruct()
{
unset(self::$_instance);
}
/**
* Impeach the clone of singleton
*/
public function __clone()
{
trigger_error('Cloning not allowed on a singleton object', E_USER_ERROR);
}
}
# EOF
you can easyli use it like that
class mySingChild extends SingletonModel
{
protected function __construct()
{
//do important things
}
public function foo()
{
echo 'hello world';
}
}
$t = mySingChild::singleton();
$t->foo();
Here's my singleton class for php 5.3.0:
<?php
class Singleton {
// this must be in every inherited singleton!
protected static $_instance;
// get the instance
final public static function instance() {
// create the instance if we don't have one
if (empty(static::$_instance)) {
$class = get_called_class(); // php 5.3.0
static::$_instance = new $class;
}
return static::$_instance;
}
// must protect the constructor
protected function __construct() { }
// overload __clone
final public function __clone() {
throw new Exception('Cannot duplicate a singleton.');
}
}
// a sample extension
class Extension extends Singleton {
// has to be here, sadly... if only statics were inherited
protected static $_instance;
protected function __construct() { ... }
public function foo() {
echo 'foo\n';
}
}
// example
$extension = Extension::instance();
$extension->foo(); // echo's 'foo\n' as expected
?>
Having to add "protected static $_instance" to every singleton is somewhat annoying. I tried the obvious alternative and stored all the instances within an array in the Singleton class. I ran Extension::getInstance() 1,000,000 over 10 runs to see which method was faster:
Array of $_instances: 3.47s average
Individual $_instance: 1.75s average
Considering the array of instances only had 1 key to search through, it's reasonable to assume that method would get slower as singletons are added, whereas the method above will always stay the same speed. The difference was enough for me to suffer the minor inconvenience.
Ex.2 only makes a 'Singleton' in the sense there is only one object makable.
But! you can still assign the object to other names(like making aliases). Probably not
what you usually want. Change the method a bit and you get only one unique name
for your 'Singleton'.. or else it will bark again and again!
<?php
#if you don't change example 2 you will get a $badDoggie
$badDoggie="I am constructedSorry but I'm already set.Sorry but I'm already set.
Sorry but I'm already set.Woof!Woof!Woof!";
// The singleton method
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
#return self::$instance;
}
echo "Sorry but I'm already set.";
return self::$instance; ##...wrong place for this!comment this, uncomment it above
}
?>
<?php
// This would fail because the constructor is private
#$test = new Example;
// This will always retrieve a single instance of the class
$test = Example::singleton();
$again = Example::singleton();
$and_again = Example::singleton();
$test->bark();
$again->bark();
$and_again->bark();
?>
Example of a decorator, which adds array access to any object:
<?php
class ArrayAccessDecorator implements ArrayAccess {
protected $object = null;
public function __construct($object){
$this->object = $object;
}
public function __call($method, $args){
return $this->productpart->$method($args);
}
public function __set($key, $val){
$this->object->$key = $val;
}
public function __get($key){
return $this->object->$key;
}
/* ArrayAccess */
public function offsetSet($key, $value){
$this->__set($key, $value);
}
public function offsetGet($key){
return $this->__get($key);
}
public function offsetUnset($key){
$this->__set($key, null);
}
public function offsetExists($offset){
$test = $this->object->__get($offset);
if($test !== null){
return true;
} else {
return false;
}
}
}
$stdobject = (object)array('test'=>'test', 'test2' => 'test2');
$arr = new ArrayAccessDecorator($stdobject);
print $arr['test']; // test
$arr['test'] = 'hello';
print $arr['test']; // hello
?>
This class will let you chain objects together into a chain. You can forward a message into the chain. The message propagates upwards into the chain until an object can handle it and returns a value. Then the return value is send backwards into the chain until it reached the caller.
This can be useful in various situations, where flexibility is needed.
In the begin of the chain we put more specialized methods, which will handle special cases (like user defined objects, json code, xml etcetera). And in the back more general (strings, array's). Now we can pass data to the chain and always get valid and safe html back. If we encounter a new data type we just put on the head of the chain a new object, which can handle this type of data.
<?php
abstract class Chainable {
protected $next = null;
protected $prev = null;
protected $res = null;
public function forward(Message $object){
if($return = $this->run($object)){
return $this->backward($return);
}
if($this->next !== null){
return $this->next->forward($object);
} else {
throw new Exception('No object can handle this type');
}
}
public function backward(Message $object){
if($this->prev === null){
return $object;
} else {
return $this->prev->backward($object);
}
}
abstract public function run(Message $object);
public function addLink(Chainable $link){
if($this->next !== null){
$this->next->addLink($link);
} else {
$this->next = $link;
$this->next->setPrevLink($this);
}
return $this;
}
protected function setPrevLink(Chainable $link){
$this->prev = $link;
return $this;
}
}
?>
Also needed the message object:
<?php
class Message {
protected $data;
public function __construct($data){
$this->data = $data;
}
public function getMessage(){
return $this->data;
}
public function setMessage($data){
$this->data = $data;
}
public function __toString(){
return (string)$this->data;
}
}
?>
The Singleton class version wich is useable by only extending it :
you would use is for example like this :
<?php
class Users extends Singleton
{
// ...
public function SomeMethod()
{
}
}
?>
and in your code :
<?php
Users::inst()->SomeMethod();
?>
I didn't check for performance, but here is the code :
<?php
class Singleton
{
// Hold an instance of the class
private static $instances = array();
// A private constructor; prevents direct creation of object
final private function __construct()
{
}
// Prevent users to clone the instance
final public function __clone()
{
trigger_error( 'Clone is not allowed.', E_USER_ERROR );
}
// The singleton method
final public static function inst()
{
$c = get_called_class();
if( ! isset( self::$instances[$c] ) )
{
self::$instances[$c] = new $c;
}
return self::$instances[$c];
}
}
?>
<?php
/**
* Class Singleton is a generic implementation of the singleton design pattern.
*
* Extending this class allows to make a single instance easily accessible by
* many other objects.
*
* @author Quentin Berlemont <quentinberlemont@gmail.com>
*/
abstract class Singleton
{
/**
* Prevents direct creation of object.
*
* @param void
* @return void
*/
protected function __construct() {}
/**
* Prevents to clone the instance.
*
* @param void
* @return void
*/
final private function __clone() {}
/**
* Gets a single instance of the class the static method is called in.
*
* See the {@link http://php.net/lsb Late Static Bindings} feature for more
* information.
*
* @param void
* @return object Returns a single instance of the class.
*/
final static public function getInstance()
{
static $instance = null;
return $instance ?: $instance = new static;
}
}
?>
E.g.
<?php
// Foo class
class Foo extends FrameworkCoreSingleton
{
// Bar method
public function bar()
{
echo __CLASS__ . PHP_EOL;
}
}
// Returns a single instance of Foo class
$foo = Foo::getInstance();
// Prints: Foo
$foo->bar();
?>
Best regards,
Quentin.
Php needs macros! That's right php seems almost unusable sometimes without precompiler. Fortunately you can generate php code with php and (easily) cache it so you can still take advantage of the php optimizing capabilities. It just creates a mess when debugging, no big deal ;)
You need to extend the language to your own needs.
But this singleton business might just work without without macros, not that nicely though.
<?php
class Singleton {
private static $instance;
public static function singleton($class = __CLASS__) {
if (!isset(self::$instance))
self::$instance = array();
if (!isset(self::$instance[$classname]))
self::$instance[$classname] = new $classname;
return self::$instance[$classname];
}
}
class SubClass extends Singleton {
public static function singleton($class = __CLASS__) {
return parent::singleton($class);
}
}
class SubSubClass extends SubClass {
public static function singleton($class = __CLASS__) {
return parent::singleton($class);
}
}
?>
As you can see, the static $instance can be an associative array holding all the instances of derived classes, but you still can't work around overriding the singleton/getInstance static method... That's what macros or language extensions would be for...
<?php
class SINGLETON(SubClass) {
/*...*/
}
?>
Translate to:
<?php
class SubClass extends Singleton {
public static function singleton($class = __CLASS__) {
return parent::singleton($class);
}
/*...*/
}
?>
Singleton in php doesn't responded like java (or others), the static instance resets on every request......
I've come up with an interesting and intuitive way to define a generic Factory class. It's basically an empty object that remembers all operations you perform on it. You can then request an actual instance, and all operations are repeated on that instance. The order of the operations is preserved.
<?php
# If you want a factory that initializes an object like this:
$myobject = new MyObject('arg1', 'arg2');
$myobject->doFooBar();
$myobject->baz = 10;
# You write:
$f_myobject = new MagicFactory('MyObject', 'arg1', 'arg2');
$f_myobject->doFooBar();
$f_myobject->baz = 10;
# You can now get the same object like this:
$myobject = $f_myobject->instance();
?>
<?php
/**
* Generic Factory class
*
* This Magic Factory will remember all operations you perform on it,
* and apply them to the object it instantiates.
*
*/
class MagicFactory {
private $history, $class, $constructor_args;
/**
* Create a factory of given class. Accepts extra arguments to be passed to
* class constructor.
*/
function __construct( $class ) {
$args = func_get_args();
$this->class = $class;
$this->constructor_args = array_slice( $args, 1 );
}
function __call( $method, $args ) {
$this->history[] = Array(
'action' => 'call',
'method' => $method,
'args' => $args
);
}
function __set( $property, $value ) {
$this->history[] = Array(
'action' => 'set',
'property' => $property,
'value' => $value
);
}
/**
* Creates an instance and performs all operations that were done on this MagicFactory
*/
function instance() {
# use Reflection to create a new instance, using the $args
$reflection_object = new ReflectionClass( $this->class );
$object = $reflection_object->newInstanceArgs( $this->constructor_args );
# Alternative method that doesn't use ReflectionClass, but doesn't support variable
# number of constructor parameters.
//$object = new $this->class();
# Repeat all remembered operations, apply to new object.
foreach( $this->history as $item ) {
if( $item['action'] == 'call' ) {
call_user_func_array( Array( $object, $item['method'] ), $item['args'] );
}
if( $item['action'] == 'set' ) {
$object->{$item['property']} = $item['value'];
}
}
# Done
return $object;
}
}
?>
Example:
<?php
class Person {
private $name, $sirname;
public $age;
function __construct( $name, $sirname ) {
$this->name = $name;
$this->sirname = $sirname;
}
function setName( $name ) {
$this->name = $name;
}
function introduce() {
print "Hello, my name is {$this->name} {$this->sirname}! I'm {$this->age} years old.";
}
}
# Setup a factory
$person_factory = new MagicFactory('Person', 'John', 'Johnson');
$person_factory->setName('Jack');
$person_factory->age = 55;
# Get an instance
$jack = $person_factory->instance();
$jack->introduce();
# Prints:
# Hello, my name is Jack Johnson! I'm 55 years old
It is possible to use every class
as if it is a singleton with a little abstraction.
I wrote some code to show you:
<?php
class MyEngine{ /* static */
static $singletons=array();
static function singletonizer($classname,$classarguments=array()){
$sca=serialize($classarguments);
if (!isset(MyEngine::$singletons[$classname][$sca])) {
if (!class_exists($classname))
/* auto loader, add error reporting for missing classes etc */
include("classes/".$classname."/.class.php");
MyEngine::$singletons[$classname][$sca]
=& new $classname($classarguments);
}
/* this is the pointer/reference and not a new object! */
return MyEngine::$singletons[$classname][serialize($classarguments)];
}
static function debug($msg,$data=""){
echo "<pre>".$msg."\t".print_r($data,1)."</pre>\r\n";
}
}
?>
Now let's test it!
Defining a class:
<?php
class testclass{
private $value;
function __construct($args){
MyEngine::debug("- testclass contructed with ",$args);
if (isset($args["value"]))
$this->set($args["value"]);
else
$this->value=0;
}
public function set($value){
$this->value = $value;
MyEngine::debug("- testclass set value =",$this->value);
}
public function get(){
MyEngine::debug("- testclass get value =",$this->value);
return $this->value;
}
}
?>
And here we run a testcase:
<?php
$args=array("value"=>12);
MyEngine::debug('create $a','expecting: contruct and set 12');
$a=MyEngine::singletonizer("testclass",$args);
$a->set(13);
MyEngine::debug('create $b','expecting: just load it. should be 13, no contruct');
$b=MyEngine::singletonizer("testclass",$args);
MyEngine::debug("b value is (expecting 13)",$b->get());
$args=array("value"=>11);
MyEngine::debug('create $c','different args -> new construct, set 11');
$c=MyEngine::singletonizer("testclass",$args);
MyEngine::debug("c value is (expecting 11)",$c->get());
$args=array("value"=>12);
MyEngine::debug('create $d','recognize args, load it, should be 13');
$d=MyEngine::singletonizer("testclass",$args);
MyEngine::debug("d value is (expecting 13)",$d->get());
?>
feedback welcome!
HTH :)
Patrick from Berlin, Germany
This is a simple Command Pattern example which performs Undo operation on a calculator. You may use callbacks in order to verify open-close principle.
<?php
abstract class Command {
abstract public function unExecute ();
abstract public function Execute ();
}
class concreteCommand extends Command {
private $operator,$operand,$calculator;
public function __construct ($calculator,$operator,$operand) {
$this->operator = $operator;
$this->operand = $operand;
$this->calculator = $calculator;
}
public function Execute() {
$this->calculator->Action($this->operator,$this->operand);
}
public function unExecute () {
$this->calculator->Action($this->Undo($this->operator),$this->operand);
}
private function Undo ($operator) {
switch ($operator) {
case '+': return '-';
case '-': return '+';
case '*': return '/';
case '/': return '*';
}
}
}
class Calculator {
private $current;
public function __construct() {
$this->current = 0;
}
public function Action($operator,$operand) {
switch ($operator) {
case '+':
$this->current += $operand;
break;
case '-':
$this->current -= $operand;
break;
case '*':
$this->current *= $operand;
break;
case '/':
$this->current /= $operand;
break;
}
}
public function getCurrent() {
return $this->current;
}
}
class Invoker {
private $commands,$calculator,$current;
public function __construct() {
$current =-1;
}
public function Undo() {
if ($this->current >= 0) {
$this->commands[$this->current]->unExecute();
$this->current--;
}
}
public function Compute($command) {
$command->Execute();
$this->current++;
$this->commands[$this->current] = $command;
}
}
?>
Example Usage:
<?php
$User = new Invoker();
$calculator = new Calculator();
$command = new concreteCommand($calculator,'+',5);
$User->Compute($command);
echo "After +5: ".$calculator->getCurrent()."<br/>";
$command = new concreteCommand($calculator,'*',7);
$User->Compute($command);
echo "After *7: ".$calculator->getCurrent()."<br/>";
$command = new concreteCommand($calculator,'/',2);
$User->Compute($command);
echo "After /2: ".$calculator->getCurrent()."<br/>";
$command = new concreteCommand($calculator,'-',10);
$User->Compute($command);
echo "After -10: ".$calculator->getCurrent()."<br/>";
$User->Undo();
echo "Undo Operation: ".$calculator->getCurrent()."<br/>";
$User->Undo();
echo "Undo Operation: ".$calculator->getCurrent()."<br/>";
$User->Undo();
echo "Undo Operation: ".$calculator->getCurrent()."<br/>";
$User->Undo();
echo "Undo Operation: ".$calculator->getCurrent()."<br/>";
?>
and Output:
After +5: 5
After *7: 35
After /2: 17.5
After -10: 7.5
Undo Operation: 17.5
Undo Operation: 35
Undo Operation: 5
Undo Operation: 0