先看看《PHP高级程序设计——模式、框架与测试》(Pro PHP——Patters, Frameworks, Testing and More)中的例子(书中每18页):
- class Database {
- private $_db;
- static $_instance;
- private function __construct() {
- $this->_db = pg_connect('dbname=example_db');
- }
- private function __clone() {}; //此处中译本漏掉了function关键字
- public static function getInstance() {
- if ( ! (self::$_instance instanceof self) ) {
- self::$_instance = new self();
- }
- return self::$_instance;
- }
- public function query($sql) {
- return pg_query($this->_db, $sql);
- }
- }
这里面有个问题,就是用继承的方式可以使用构造函数生成子类的对象,可能在不小心的情况下破坏了单件机制。代码如下:
- class subDatabase
- {
- public function __construct()
- {
- $this->_db = pg_connect('dbname=example_db');
- }
- }
在JAVA中,这种情况是不会出现的,这是因为JAVA的构造函数无论显式或隐式,都必须调用父类的构造函数,而父类的构造函数一旦被设置为private,就不能为子类访问。因此,拥有私有构造函数的类将不能被子类化(继承)。
而在PHP中,构造函数无须显式或隐式地调用父类的构造函数,就造成了上面的情况。
堵住这个漏洞的办法也很简单,只要将Database的构造函数设置为final,子类将无法对其进行重写,虽然仍然能够子类化该类,但却无法实例化。
代码如下:
- class Database {
- private $_db;
- static $_instance;
- final private function __construct() {
- $this->_db = pg_connect('dbname=example_db');
- }
- private function __clone() {}; //此处中译本漏掉了function关键字
- public static function getInstance() {
- if ( ! (self::$_instance instanceof self) ) {
- self::$_instance = new self();
- }
- return self::$_instance;
- }
- public function query($sql) {
- return pg_query($this->_db, $sql);
- }
- }
更简单的方式,给类添加final,使其无法被继承:
- final class Database {
- private $_db;
- static $_instance;
- private function __construct() {
- $this->_db = pg_connect('dbname=example_db');
- }
- private function __clone() {}; //此处中译本漏掉了function关键字
- public static function getInstance() {
- if ( ! (self::$_instance instanceof self) ) {
- self::$_instance = new self();
- }
- return self::$_instance;
- }
- public function query($sql) {
- return pg_query($this->_db, $sql);
- }
- }
- public class Singleton{
- private static Singleton singleton = new Singleton ();
- private Singleton (){}
- public Singleton getInstance(){
- return singletion;
- }
- }