如何使用PHP5类创建单例类?
当前回答
不幸的是,当有多个子类时,Inwdr的答案就失效了。
下面是一个正确的可继承单例基类。
class Singleton
{
private static $instances = array();
protected function __construct() {}
protected function __clone() {}
public function __wakeup()
{
throw new Exception("Cannot unserialize singleton");
}
public static function getInstance()
{
$cls = get_called_class(); // late-static-bound class name
if (!isset(self::$instances[$cls])) {
self::$instances[$cls] = new static;
}
return self::$instances[$cls];
}
}
测试代码:
class Foo extends Singleton {}
class Bar extends Singleton {}
echo get_class(Foo::getInstance()) . "\n";
echo get_class(Bar::getInstance()) . "\n";
其他回答
PHP 5.3允许通过后期静态绑定创建可继承的单例类:
class Singleton
{
protected static $instance = null;
protected function __construct()
{
//Thou shalt not construct that which is unconstructable!
}
protected function __clone()
{
//Me not like clones! Me smash clones!
}
public static function getInstance()
{
if (!isset(static::$instance)) {
static::$instance = new static;
}
return static::$instance;
}
}
这解决了一个问题,在PHP 5.3之前,任何扩展了Singleton的类都会生成父类的实例,而不是它自己的实例。
现在你可以做:
class Foobar extends Singleton {};
$foo = Foobar::getInstance();
$foo将是Foobar的一个实例而不是Singleton的一个实例。
我知道这可能会引起不必要的争论,但是我知道您可能需要多个数据库连接,所以我承认单例可能不是最好的解决方案……然而,我发现单例模式还有其他非常有用的用途。
Here's an example: I decided to roll my own MVC and templating engine because I wanted something really lightweight. However, the data that I want to display contains a lot of special math characters such as ≥ and μ and what have you... The data is stored as the actual UTF-8 character in my database rather than pre-HTML-encoded because my app can deliver other formats such as PDF and CSV in addition to HTML. The appropriate place to format for HTML is inside the template ("view" if you will) that is responsible for rendering that page section (snippet). I want to convert them to their appropriate HTML entities, but PHPs get_html_translation_table() function is not super fast. It makes better sense to retrieve the data one time and store as an array, making it available for all to use. Here's a sample I knocked together to test the speed. Presumably, this would work regardless of whether the other methods you use (after getting the instance) were static or not.
class EncodeHTMLEntities {
private static $instance = null;//stores the instance of self
private $r = null;//array of chars elligalbe for replacement
private function __clone(){
}//disable cloning, no reason to clone
private function __construct()
{
$allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
$specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
$this->r = array_diff($allEntities, $specialEntities);
}
public static function replace($string)
{
if(!(self::$instance instanceof self) ){
self::$instance = new self();
}
return strtr($string, self::$instance->r);
}
}
//test one million encodings of a string
$start = microtime(true);
for($x=0; $x<1000000; $x++){
$dump = EncodeHTMLEntities::replace("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)");
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds using singleton\n";
//now repeat the same without using singleton
$start = microtime(true);
for($x=0; $x<1000000; $x++){
$allEntities = get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES);
$specialEntities = get_html_translation_table(HTML_SPECIALCHARS, ENT_NOQUOTES);
$r = array_diff($allEntities, $specialEntities);
$dump = strtr("Reference method for diagnosis of CDAD, but clinical usefulness limited due to extended turnaround time (≥96 hrs)", $r);
}
$end = microtime(true);
echo "Run time: ".($end-$start)." seconds without using singleton";
基本上,我看到的典型结果如下:
php test.php Run time: 27.842966794968 seconds using singleton Run time: 237.78191494942 seconds without using singleton
因此,虽然我不是专家,但我认为没有更方便、更可靠的方法来减少对某些数据的缓慢调用的开销,同时使其超级简单(只需一行代码就可以完成所需的工作)。假设我的例子只有一个有用的方法,因此并不比一个全局定义的函数好,但是一旦你有了两个方法,你就想把它们组合在一起,对吗?我是不是太离谱了?
此外,我更喜欢真正做一些事情的例子,因为有时很难想象一个例子中包含“//在这里做一些有用的事情”这样的语句,这是我在搜索教程时经常看到的。
无论如何,我希望有任何关于为什么在这种情况下使用单例是有害的(或过于复杂)的反馈或评论。
以上答案都是可以的,但我还会再补充一些。
无论谁在2021年来到这里,我都将展示另一个使用单例模式类作为trait的例子,并在任何类中重用它。
<?php
namespace Akash;
trait Singleton
{
/**
* Singleton Instance
*
* @var Singleton
*/
private static $instance;
/**
* Private Constructor
*
* We can't use the constructor to create an instance of the class
*
* @return void
*/
private function __construct()
{
// Don't do anything, we don't want to be initialized
}
/**
* Get the singleton instance
*
* @return Singleton
*/
public static function getInstance()
{
if (!isset(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Private clone method to prevent cloning of the instance of the
* Singleton instance.
*
* @return void
*/
private function __clone()
{
// Don't do anything, we don't want to be cloned
}
/**
* Private unserialize method to prevent unserializing of the Singleton
* instance.
*
* @return void
*/
private function __wakeup()
{
// Don't do anything, we don't want to be unserialized
}
}
所以,像在任何课堂上一样轻松地使用它。假设,我们想在UserSeeder类中实现单例模式。
<?php
class UserSeeder
{
use Singleton;
/**
* Seed Users
*
* @return void
*/
public function seed()
{
echo 'Seeding...';
}
}
这是在数据库类上创建单例的例子
设计模式 1)单
class Database{
public static $instance;
public static function getInstance(){
if(!isset(Database::$instance)){
Database::$instance=new Database();
return Database::$instance;
}
}
$db=Database::getInstance();
$db2=Database::getInstance();
$db3=Database::getInstance();
var_dump($db);
var_dump($db2);
var_dump($db3);
那么输出是
object(Database)[1]
object(Database)[1]
object(Database)[1]
只使用单个实例,不要创建3个实例
class Database{
//variable to hold db connection
private $db;
//note we used static variable,beacuse an instance cannot be used to refer this
public static $instance;
//note constructor is private so that classcannot be instantiated
private function __construct(){
//code connect to database
}
//to prevent loop hole in PHP so that the class cannot be cloned
private function __clone() {}
//used static function so that, this can be called from other classes
public static function getInstance(){
if( !(self::$instance instanceof self) ){
self::$instance = new self();
}
return self::$instance;
}
public function query($sql){
//code to run the query
}
}
Access the method getInstance using
$db = Singleton::getInstance();
$db->query();
推荐文章
- 在PHP5中创建单例设计模式
- 什么时候我们应该使用观察者和可观察对象?
- 阻止人们入侵基于php的Flash游戏高分表的最佳方法是什么
- PHP子字符串提取。获取第一个'/'之前的字符串或整个字符串
- __construct函数的作用是什么?
- PHP中的异步shell执行器
- Laravel 5 -如何访问在视图存储上传的图像?
- 为什么在PHP中使用sprintf函数?
- “质量分配”在Laravel中是什么意思?
- 在逗号上爆炸字符串,并修剪每个值的潜在空格
- PHP与MySQL 8.0+错误:服务器请求身份验证方法未知的客户端
- laravel5“LIKE”对等物(雄辩的)
- 在函数中使用默认实参
- 转换php数组到Javascript
- PHP PDO:字符集,集名称?