singletons in php - why they are bad and how you can eliminate them from your applications
DESCRIPTION
While Singletons have become a Pattern-Non-Grata over the years, you still find it surprisingly often in PHP applications and frameworks. This talk will explain what the Singleton pattern is, how it works in PHP and why you should avoid it in your application.TRANSCRIPT
![Page 1: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/1.jpg)
Singletons inSingletons in Why they are bad and how you can eliminate
them from your applications
![Page 2: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/2.jpg)
Gordon OheimGordon Oheim@go_oh
![Page 3: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/3.jpg)
![Page 4: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/4.jpg)
a.k.a.The GoF Book
![Page 5: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/5.jpg)
Singleton
![Page 6: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/6.jpg)
Creational Pattern„control when and how objects are
created“
![Page 7: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/7.jpg)
“Ensure a class has only one instance, and provide a global
access point to it.”
![Page 8: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/8.jpg)
Singleton- instance : Singleton+ getInstance() : Singleton- __construct() : void- __clone() : void- __wakeup() : void
Singleton- instance : Singleton+ getInstance() : Singleton- __construct() : void- __clone() : void- __wakeup() : void
![Page 9: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/9.jpg)
class Singleton… public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self; } return self::$instance; }}
![Page 10: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/10.jpg)
abstract class Singleton… public static function getInstance() { return isset(static::$instance) ? static::$instance : static::$instance = new static; } final private function __construct() { static::init(); } protected function init() {}}class A extends Singleton { protected static $instance;}
![Page 11: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/11.jpg)
trait Singleton… protected static $instance; final public static function getInstance() { return isset(static::$instance) ? static::$instance : static::$instance = new static; } final private function __construct() { static::init(); } protected function init() {}}class A { use Singleton;}
![Page 12: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/12.jpg)
„Nobody should need a mechanism to make it as easy as pie to clutter the code base
with singletons“
- Sebastian Bergmann
![Page 13: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/13.jpg)
Testing Singletons
![Page 14: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/14.jpg)
„In my stilted view of the universe anything that impedes testing is something to be avoided. There are those who don't agree with this view, but I'll
pit my defect rates against theirs any time.“
- Robert „Uncle Bob“ C. Martin
![Page 15: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/15.jpg)
class TableDataGateway… public function __construct() { $this->db = Db::getInstance(); } public insert(array $data) { $this->db->sql('INSERT …', $data); }}
![Page 16: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/16.jpg)
class TableDataGatewayTest extends PHPUnit… /**
* @dataProvider provideInsertData */
public function testInsertCallsDbWithData($data) { $gateway = new TableDataGateway; $gateway->insert($data); $this->assertSame( $data, $gateway->findById($data['id']) ); }}
![Page 17: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/17.jpg)
throws LogicException: No key found for 'pdo' in Registry
![Page 18: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/18.jpg)
class Db extends Singleton… protected function init() { $this->logger = Logger::getInstance(); $this->pdo = new PDO(Registry::get('pdo')); } public sql($query, $data) { $this->logger->log(printf( 'Executed %s with %s', $query, implode(',', $data) )); $sth = $this->pdo->prepare($query); return $sth->execute($data); } }
![Page 19: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/19.jpg)
Singletons are pathological liars- Miško Hevery
![Page 20: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/20.jpg)
class TableDataGatewayTest extends PHPUnit… /**
* @dataProvider provideInsertData */
public function testInsertCallsDbWithData($data) { Registry::set('pdo', array('…')); Registry::set('log', '/dev/null'); $gateway = new TableDataGateway; $gateway->insert($data); $this->assertSame( $data, $gateway->findById($data['id']) ); }}
![Page 21: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/21.jpg)
Your tests are not isolated.You still need a real database.
No easy way to mock the Db Singleton.
![Page 22: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/22.jpg)
„The real problem with Singletons is that they give you such a good excuse not to think carefully
about the appropriate visibility of an object.“
- Kent Beck
![Page 23: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/23.jpg)
Hard to change code manifests itself in a cascade of
subsequent changes in dependent code
![Page 24: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/24.jpg)
Fragile code breaks in many places when you
change just one place
![Page 25: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/25.jpg)
Non-reusable code is code that you cannot reuse in
another project because it contains too much extra baggage
![Page 26: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/26.jpg)
S.O.L.I.D.
![Page 27: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/27.jpg)
Single Responsibility Principle
A class should have one, and only one, reason to change.
![Page 28: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/28.jpg)
Open Closed Principle
You should be able to extend a classes behavior, without modifying it.
![Page 29: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/29.jpg)
Liskov Substitution Principle
Derived classes must be substitutable for their base classes.
![Page 30: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/30.jpg)
Interface Segregation Principle
Make fine grained interfaces that are client specific.
![Page 31: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/31.jpg)
Dependency Inversion PrincipleDepend on abstractions, not on concretions.
![Page 32: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/32.jpg)
Solid Singleton?
![Page 33: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/33.jpg)
SRP Violation
Creation Logic + Business Logic= 2 reasons to change
Mitigated by using Abstract Singletons
But responsibilities are still strongly coupled through inheritance
![Page 34: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/34.jpg)
OCP Violation
In PHP < 5.2 Singletons are closed for extending
Boilerplate code has to be removed when no longer needed
![Page 35: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/35.jpg)
DIP Violation
Global access breaks encapsulation
Hides dependencies
Adds concrete dependencies into Clients
Signature lies
![Page 36: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/36.jpg)
Singletons in the Wild
![Page 37: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/37.jpg)
Database
FrontController
Logger
Cache
Registry
Request
ResponseConfig
Bootstrap
Application
Acl
FooController
BarController
ThisService
ThatService
![Page 38: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/38.jpg)
Database
FrontController
Logger
Cache
Registry
Request
ResponseConfig
Bootstrap
Application
Acl
FooController
BarController
ThisService
ThatService
![Page 39: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/39.jpg)
Recap:“Ensure a class has only one
instance, and provide a global access point to it.”
![Page 40: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/40.jpg)
„So much of the Singleton pattern is about coaxing language protection mechanisms into
protecting this one aspect: singularity. I guess it is important, but it seems to have grown out of
proportion.“
- Ward Cunningham
![Page 41: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/41.jpg)
You do not need to ensure singularity when you are going to instantiate the
object only once anyway.
![Page 42: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/42.jpg)
You do not need to provide a Global Access Point when you can inject the
object.
![Page 43: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/43.jpg)
class TableDataGateway… public function __construct() { $this->db = Db::getInstance(); }}class Db extends Singleton… protected function init() { $this->logger = Logger::getInstance(); $this->pdo = new PDO(Registry::get('pdo')); } }
![Page 44: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/44.jpg)
class TableDataGateway… public function __construct(Db $db) { $this->db = $db; }}class Db… public function __construct(PDO $pdo, Log $logger) { $this->logger = $logger; $this->pdo = $pdo; } }
![Page 45: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/45.jpg)
But then I have to push dependencies all the way through my object graph?!
![Page 46: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/46.jpg)
Recap: Creational Pattern
„control when and how objects are created“
![Page 47: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/47.jpg)
Use Builders and Factories to create Collaborator Graphs
![Page 48: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/48.jpg)
class UserControllerBuilder { public function build($config) { $log = new Log($config['log']); $pdo = new PDO($config['…']); $db = new Db($pdo, $log); $tdg = new TableDataGateway($db); return new UserController($tdg); }}
![Page 49: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/49.jpg)
class UserControllerBuilder { public function build($config) { $log = new Log($config['log']); $pdo = new PDO($config['…']); $db = new Db($pdo, $log); $tdg = new TableDataGateway($db); return new UserController($tdg); }}
???
![Page 50: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/50.jpg)
class UserControllerBuilder { public function build($config) { $db = new LogDecorator( new PDO($config['…']); new Log($config['log']); ); $tdg = new TableDataGateway($db); return new UserController($tdg); }}
![Page 51: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/51.jpg)
// index.phpinclude '/path/to/autoload.php';$config = new Config('/path/to/config.ini');$router = new Router( array( '/user/{id}' => function() use ($config) { $builder = new UserControllerBuilder; return $builder->build($config); } ));$router->route( new Request($_GET, $_POST, $_SERVER), new Response);
![Page 52: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/52.jpg)
„Singletons aren't necessary when you can design or redesign
to avoid using them.“
- Joshua Kerievsky
![Page 53: Singletons in PHP - Why they are bad and how you can eliminate them from your applications](https://reader036.vdocuments.us/reader036/viewer/2022062617/54b79a984a79591d4a8b47fa/html5/thumbnails/53.jpg)
„I'm in favor of dropping Singleton. Its use is almost always a design
smell“
- Erich Gamma