PHP中的单例模式实现

在面向对象编程中,设计模式是一种常用的解决特定问题的模板。其中,单例模式是一种确保一个类只有一个实例,并提供一个全局访问点的模式。在PHP中,自5.0版本以来,它已经是一个完全面向对象的语言,许多设计模式,包括单例模式,也被广泛应用于PHP及其众多的MVC框架中。本文将通过一步步的方法来实现PHP中的单例模式,并解决可能遇到的问题。

场景

PHP开发中(尤其是使用MVC框架时),经常需要包含/引入一个数据库类、上传类或Cookie类,如下所示:

<?php require 'DB.class.php'; require 'Upload.class.php'; require 'Cookie.class.php'; // 但需要确保只有一个DB或Cookie类的实例,因为一个实例就足够了,更多实例将会引起问题。这时,单例模式就派上用场了。

单例模式简而言之,就是如果一个程序员已经实例化了一个特定类的实例,那么另一个程序员就不能实例化第二个。现在,让从头开始看看如何实现它。

实现步骤

创建一个名为Singleton的类,现在可以实例化任意数量的对象。这里可以使用Singleton类创建两个对象:

class Singleton { } $s1 = new Singleton(); $s2 = new Singleton(); // 那么$s1和$s2是同一个对象吗?当然不是,可以通过一个简单的if语句来判断:

注意:在判断两个对象是否为同一个对象时,必须使用“===”,而不是“==”。

如果想要阻止类用户创建他们想要的任意数量的Singleton类对象,该怎么做呢?可能认为对象是通过类的构造函数创建的。那么,为什么不把构造函数隐藏在类内部,这样外部就无法使用它,如下代码所示:

class Singleton2 { protected function __construct() { } } $s3 = new Singleton2(); // 致命错误:从无效的上下文中调用受保护的Singleton2::__construct()

现在可以看到,把构造函数设为受保护的,但新问题是:没有人可以再创建对象了。

为了让类用户能够创建对象,需要留下一个对象创建的“接口”,所以添加了一个名为getIns()的新方法,它是public(对外开放)和static(可以类名调用)的:

class Singleton3 { public static function getIns() { return new self(); } protected function __construct() { } } // 只是在类内部创建了一个类本身的实例,然后返回它。现在再次测试:

结果仍然是:s4和s5不是同一个对象。这两个对象仍然不是同一个对象,为什么?因为Singleton3::getIns()被调用了两次,因此创建了两个对象。但现在,控制权在手中,可以改进getIns()以实现想要的结果。

现在可以在getIns()中添加一些检查:

class Singleton4 { protected static $ins = NULL; public static function getIns() { if (self::$ins === null) { self::$ins = new self(); } return self::$ins; } protected function __construct() { } } // 现在在类的一个受保护属性$ins中存储类的实例。然后当getIns()被调用时,在这里进行一些检查:如果$ins是NULL,那么实例化一个类对象。最后,返回self::$ins。

让测试一下:

$s6 = Singleton4::getIns(); $s7 = Singleton4::getIns(); if ($s6 === $s7) { echo 's6和s7是同一个对象'; } else { echo 's6和s7不是同一个对象'; } // 输出:s6和s7是同一个对象

现在得到了想要的结果!现在类只有一个实例了。但这还不够,如果有另一个类叫做Multi,它继承了原始类:

现在需要在父构造函数前加上final关键字:

class Singleton5 { protected static $ins = NULL; public static function getIns() { if (self::$ins === null) { self::$ins = new self(); } return self::$ins; } // 添加final,所以这个方法不能被覆盖! final protected function __construct() { } } // 现在如果再次运行脚本:

输出:Fatal error: Cannot override final method Singleton5::__construct()。

PHP

class Singleton6 { protected static $ins = NULL; public static function getIns() { if (self::$ins === null) { self::$ins = new self(); } return self::$ins; } // 添加final,所以这个方法不能被覆盖! final protected function __construct() { } // 禁止克隆 final protected function __clone() { } } $s10 = Singleton6::getIns(); $s11 = clone $s10; // Fatal error: Call to protected Singleton6::__clone()

现在克隆是不可能的。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485