note 58324 added to language.oop5.patterns

From: Date: Mon, 31 Oct 2005 15:57:35 +0000
Subject: note 58324 added to language.oop5.patterns
Groups: php.notes 
Request: Send a blank email to php-notes+get-97883@lists.php.net to get a copy of this message
@ steffen at morkland dot com: Interesting problem and u are right about always having to put the non-public constructor and public singleton-method in the classes that need to be singletons. U are also right about an interface not being able to declare a constructor private or protected. Why not store all singletons in a static variable of a common parent class and make singleton-capability available to all childclasses? We can accomplish this by adding a hybrid singletonFactory()-method in that parent class and make the constructor of the childclass protected to enforce the singleton-pattern. At this moment all childclasses can be a singleton! Not to robust. U can have childclasses implement the Singleton-interface as specified in ur post so classes can be tested on implementing this interface. If u always implement the interface on ur singleton-classes u can add a test to the singletonFactory()-method to check whether the class u are about to instantiate does implement the Singleton-interface. Together with the enforced prototyping of the singleton()-method this provides a more foolproof usage of the singleton-pattern. The singleton code is implemented in the parent so no rewriting of the code is necessary, thus avoiding programmer mistakes in the childclasses and keeping the code cleaner to the eye. The only methods the childclass needs are a protected constructor to avoid direct instantiation and a wrapping singleton()-method. <?php // As stated by steffen we can't restrict visibility of the constructor in an interface interface Singleton { public static function singleton(); } // Parent class: // U can define these methods at the highest level so the singleton-functionality // is available to all objects, but it works at all levels of an object hierarchy. class ParentClass { private static $childSingletons = array(); // store singletons for each childclass public static function singletonFactory($class='') { if (!isset(self::$childSingletons[$class])) { // singleton not loaded? if (include_once($class.'.php')) { // classfile included? $thisClass = __CLASS__; $object = new $class; if ($object instanceof $thisClass) { // class is childclass? (so we can access the protected constructor) $classImplements = class_implements($object); if (isset($classImplements['Singleton'])) { // class implements Singleton? self::$childSingletons[$class] = new $class; } else { throw new Exception ('Class \''.$class.'\' does not implement interface Singleton'); } } else { throw new Exception ('Unknown class \''.$class.'\''); } } else { throw new Exception ('Class \''.$class.'\' not found'); } } return self::$childSingletons[$class]; } } // Child class: // 1. Define the constructor as protected. // 2. Implement interface Singleton ... // ... to enforce prototype of singleton() // ... to be able to dynamically identify the class as a singleton. // 3. Define the singleton()-method acting as a wrapper for the parent's singletonFactory()-method. class ChildClass extends ParentClass implements Singleton{ protected function __construct() {} public static function singleton() { return parent::singletonFactory(__CLASS__); } } // public usage $singleton = ChildClass::singleton(); ?> If u prefer more loose programming u can leave the Singleton interface out of the picture alltogether and create your childsingletons directly with the singletonFactory()-method. This approach only needs the protected constructor(), no singleton()-method. I know this approach allows all the childclasses to be treated as singletons. In my opinion this is not a problem, but the lack of robustness and absence of dynamic testability is. ;) ---- Manual Page -- http://www.php.net/manual/en/language.oop5.patterns.php Edit -- http://master.php.net/manage/user-notes.php?action=edit+58324 Delete: added to the manual -- http://master.php.net/manage/user-notes.php?action=delete+58324&report=yes&reason=added+to+the+manual Delete: bad code -- http://master.php.net/manage/user-notes.php?action=delete+58324&report=yes&reason=bad+code Delete: spam -- http://master.php.net/manage/user-notes.php?action=delete+58324&report=yes&reason=spam Delete: useless -- http://master.php.net/manage/user-notes.php?action=delete+58324&report=yes&reason=useless Delete: non-english -- http://master.php.net/manage/user-notes.php?action=delete+58324&report=yes&reason=non-english Delete: already in docs -- http://master.php.net/manage/user-notes.php?action=delete+58324&report=yes&reason=already+in+docs Delete: other reasons -- http://master.php.net/manage/user-notes.php?action=delete+58324&report=yes Reject -- http://master.php.net/manage/user-notes.php?action=reject+58324&report=yes Search -- http://master.php.net/manage/user-notes.php

« previous php.notes (#97883) next »