note 52003 added to language.oop5.patterns
| From: | richard dot quadling at bandvulc dot co dot uk | Date: | Mon, 18 Apr 2005 15:06:22 +0000 |
| Subject: | note 52003 added to language.oop5.patterns | ||
| Groups: | php.notes | ||
| Request: | Send a blank email to php-notes+get-88168@lists.php.net to get a copy of this message | ||
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.
----
Manual Page -- http://www.php.net/manual/en/language.oop5.patterns.php
Edit -- http://master.php.net/manage/user-notes.php?action=edit+52003
Delete: added to the manual -- http://master.php.net/manage/user-notes.php?action=delete+52003&report=yes&reason=added+to+the+manual
Delete: bad code -- http://master.php.net/manage/user-notes.php?action=delete+52003&report=yes&reason=bad+code
Delete: spam -- http://master.php.net/manage/user-notes.php?action=delete+52003&report=yes&reason=spam
Delete: useless -- http://master.php.net/manage/user-notes.php?action=delete+52003&report=yes&reason=useless
Delete: other reasons -- http://master.php.net/manage/user-notes.php?action=delete+52003&report=yes
Reject -- http://master.php.net/manage/user-notes.php?action=reject+52003&report=yes
Search -- http://master.php.net/manage/user-notes.php