search for in the  
<Object IterationMagic Methods>
Last updated: Thu, 19 May 2005

Patterns

Patterns are ways to describe best practices and good designs. They show a flexible solution to common programming problems.

Factory

The Factory pattern allows for the instantiation of objects at runtime. It is called a Factory Pattern since it is responsible for "manufacturing" an object.

Example 19-23. Factory Method

<?php
class Example
{
  
// The factory method
  
public static function factory($type)
   {
       if (include_once
'Drivers/' . $type . '.php') {
          
$classname = 'Driver_' . $type;
           return new
$classname;
       } else {
           throw new
Exception ('Driver not found');
       }
   }
}
?>

Defining this method in a class allows drivers to be loaded on the fly. If the Example class was a database abstraction class, loading a MySQL and SQLite driver could be done as follows:

<?php
// Load a MySQL Driver
$mysql = Example::factory('MySQL');

// Load a SQLite Driver
$sqlite = Example::factory('SQLite');
?>

Singleton

The Singleton pattern applies to situations in which there needs to be a single instance of a class. The most common example of this is a database connection. Implementing this pattern allows a programmer to make this single instance easily accessible by many other objects.

Example 19-24. Singleton Function

<?php
class Example
{
  
// Hold an instance of the class
  
private static $instance;
  
  
// A private constructor; prevents direct creation of object
  
private function __construct()
   {
       echo
'I am constructed';
   }

  
// The singleton method
  
public static function singleton()
   {
       if (!isset(
self::$instance)) {
          
$c = __CLASS__;
          
self::$instance = new $c;
       }

       return
self::$instance;
   }
  
  
// Example method
  
public function bark()
   {
       echo
'Woof!';
   }

  
// Prevent users to clone the instance
  
public function __clone()
   {
      
trigger_error('Clone is not allowed.', E_USER_ERROR);
   }

}

?>

This allows a single instance of the Example class to be retrieved.

<?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();
$test->bark();

// This will issue an E_USER_ERROR.
$test_clone = clone($test);

?>


User Contributed Notes
Patterns
dmnEe0 at gmail dot com
14-May-2005 05:13
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
?>
richard dot quadling at bandvulc dot co dot uk
19-Apr-2005 08:29
Singletons and subclasses will fail because __construct has to be public SOMEWHERE in the base class and cannot be hidden in sub classes. Even if the base class is an abstract class (which helps a little).

You can get abstract base class and singleton sub class working fine EXCEPT that you can create an instance of the subclass if you use new class(); rather than class::singleton();

So. After many hours of trial and error, no mixing of singletons and subclasses.
richard dot quadling at bandvulc dot co dot uk
19-Apr-2005 03:39
Further to my note. If you think I called the wrong method in the last line of code ...

$subclass2Instance->TellMe();

Notice I am using the SECOND subclass but a method from the FIRST subclass. This should be the clue to see that multiple subclasses of a base singleton class don't work.

If you try to call ...

$subclass2Instance->TellMeMore();

you get, as expected, a fatal error ...

Fatal error: Call to undefined method SubClass::TellMeMore()

Hope that clarifies things.
richard dot quadling at bandvulc dot co dot uk
18-Apr-2005 11:06
In response to Scott Mattocks response to Jimmy Paterson ...

You cannot mix singletons and subclasses securely.

Why?

The standard way of creating a singleton is with the method ...

   // Hold an instance of the class
   private static $instance;

   // The singleton method
   public static function singleton()
   {
       if (!isset(self::$instance)) {
           $c = __CLASS__;
           self::$instance = new $c;
       }

       return self::$instance;
   }

This returns either the previously created instance or a new instance of this class.

As the constructor is private (which inhibits the manual creation of the class), you cannot alter the value of $c in the example above by passing it to the function, as suggested by Scott Mattocks.

Why? __construct() is private!!!!

self::$instance = new $c;

where $c is NOT Singleton will result in a fatal error ...

Fatal error: Call to private Singleton::__construct().

You have to have __construct() as private, otherwise you can create multiple instances of the singleton, explicit contra the reason for the pattern to start with.

Now. Say you do make the __construct() protected (can only be called from this class or subclasses), then you MAY have a little more success.

But not much ...

<?php

class Singleton
{
 
// Hold an instance of the class
 
private static $instance;
 
 
// A private constructor; prevents direct creation of object
 
protected function __construct()
  {
     echo
'I am constructed';
  }
 
// The singleton method
 
public static function singleton($classname = __CLASS__)
  {
     if (!isset(
self::$instance)) {
        
self::$instance = new $classname;
     }
     return
self::$instance;
  }
}
class
SubClass extends Singleton {
   public static function
singleton()
   {
       return
parent::singleton(__CLASS__); // NOTE The singleton method MUST return an instance.
  
}
   public function
TellMe()
   {
       echo
'You are in here.';
   }
}

$subclassInstance = SubClass::singleton();
$subclassInstance->TellMe();
?>

gives you ...

I am constructedYou are in here.

But you are not going to be able to extend this to more than 1 subclass as the singleton exists for the base class ...

<?php

class Singleton
{
 
// Hold an instance of the class
 
private static $instance;
 
 
// A private constructor; prevents direct creation of object
 
protected function __construct()
  {
     echo
'I am constructed';
  }
 
// The singleton method
 
public static function singleton($classname = __CLASS__)
  {
     if (!isset(
self::$instance)) {
        
self::$instance = new $classname;
     }
     return
self::$instance;
  }
}
class
SubClass extends Singleton {
   public static function
singleton()
   {
       return
parent::singleton(__CLASS__); // NOTE The singleton method MUST return an instance.
  
}
   public function
TellMe()
   {
       echo
'You are in here.';
   }
}

class
SubClass2 extends Singleton {
   public static function
singleton()
   {
       return
parent::singleton(__CLASS__); // NOTE The singleton method MUST return an instance.
  
}
   public function
TellMeMore()
   {
       echo
'You are over here.';
   }
}

$subclassInstance = SubClass::singleton();
$subclassInstance->TellMe();

$subclass2Instance = SubClass2::singleton();
$subclass2Instance->TellMe();
?>

results in ...

I am constructedYou are in here.You are in here.

and NOT

I am constructedYou are in here.You are over here.

as you might have thought.

Basically, subclassing and singletons don't really mix.
scottmattocks at php dot net
06-Apr-2005 12:40
In respone to JimmyPaterson:

Since the singleton method isn't declared final, you can override it in the children classes. First you have to change the singleton class a little to accept a classname parameter.

class Singleton
{
   // Hold an instance of the class
   private static $instance;
 
   // A private constructor; prevents direct creation of object
   private function __construct()
   {
       echo 'I am constructed';
   }

   // The singleton method
   public static function singleton($classname)
   {
       if (!isset(self::$instance)) {
           self::$instance = new $classname;
       }

       return self::$instance;
   }
}

class SubClass extends Singleton {
   public static function singleton()
   {
       parent::singleton(__CLASS__);
   }
}

$singletonInstance = SubClass::singleton();
JimmyPaterson at gmx dot de
21-Mar-2005 08:55
Since the `__CLASS__` constant is used, the Singleton pattern won't work as a Base Class which you would want to implement into your classes.
Thus the following will _not_ work:
<?php

class Singleton
{
   private static
$_instance;
  
   final private function
__construct() { }
   public static function
getSingleton()
   {
     if(!isset(
self::$_instance))
     {
        
$tmpName    = __CLASS__;
        
self::$_instance = new $tmpName;
     }
     return
self::$_instance;
   }
  
   public function
NameSingletonClass()
   {
     echo
__CLASS__;
   }
   public function
__clone() { }
}

class
MyClass extends Singleton
{
   public function
NameMyClass()
   {
     echo
__CLASS__;
   }
}

$instance = MyClass::getSingleton();
$instance->NameSingletonClass();
// you'll get a nice `Call to undefined method Songleton::NameMyClass()` Error
$instance->NameMyClass();

?>
Kind of stupid if one has to write a Singleton-Pattern for each Class... or did I miss something?
Pablo
02-Feb-2005 12:56
I believe there is a typo in the factory method pattern:

// The factory method
   function &factory($type){

}

The & is not needed as objects in php5 are always passed as references.

<Object IterationMagic Methods>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 18:35:34 2005 EDT