單例模式的概念
單例模式是指整個應用中某個類只有一個對象實例的設計模式。具體來說,作爲對象的創建方式,單例模式確保某一個類只有一個實例,而且自行實例化並向整個系統全局的提供這個實例。它不會創建實例副本,而是會向單例類內部存儲的實例返回一個引用。
單例模式的特點
單例模式的主要特點是“三私一公”:
需要一個保存類的唯一實例的私有靜態成員變量
構造函數必須聲明爲私有的,防止外部程序new一個對象從而失去單例的意義
克隆函數必須聲明爲私有的,防止對象被克隆
必須提供一個訪問這個實例的公共靜態方法(通常命名爲getInstance),從而返回唯一實例的一個引用。
使用單例模式的原因及場景
在PHP的大多數應用中都會存在大量的數據庫操作,如果不用單例模式,那每次都要new操作,但是每次new都會消耗大量的系統資源和內存資源,而且每次打開和關閉數據庫都是對數據庫的一種極大考驗和浪費。所以單例模式經常用在數據庫操作類中。
同樣,如果系統中需要有一個類來全局控制某些配置信息,那使用單例模式可以很方便的實現。
通俗的理解
PHP設計模式之一,單例模式,顧名思義就是隻有一個實例。單例模式確保某一個類只有一個實例,不能重複實例,只能它自己實例化,而且向整個系統提供這個實例。
三私一公:私有化靜態屬性,私有化構造方法,私有化克隆方法,公有化靜態方法。
單例模式:即一個類只被實例化一次,當其他人對其再次實例化時,返回第一次實例化的對象,可以避免大量的new操作,減少資源的消耗,典型應用於數據庫類的實例化。
class DB {
private static $instance = null; //私有靜態屬性 存放該類的實例
private function __construct(){ // 私有構造方法 防止在類的外部實例化
// 實現
}
private function __clone(){ // 私有克隆方法 防止克隆
// 實現
}
public static function getInstance(){ //公共的靜態方法 實例化該類本身且只實例化一次
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
}
class Singleton {
public $name;
private static $instance = null;
private function __construct(){
}
public function __clone(){
}
public static function getInstance(){
if(empty(self::$instance)){
self::$instance = new self();
}
return self::$instance;
}
public function set($name){
$this->name = $name;
}
}
$obj1 = Singleton::getInstance();
$obj2 = Singleton::getInstance();
$obj1->set("aaa");
$obj2->set("bbb");
echo $obj1->name; // 輸出結果:bbb
echo $obj2->name; // 輸出結果:bbb
// 原因:單例模式只new一次,開闢一塊空間,所以後續的實例都是操作的同一塊空間
// 引用easyswoole裏的單例實現
// 首先,他們的區別只有在繼承中才能體現出來,如果沒有任何繼承,那麼這兩者是沒有區別的。
// 然後,new self()返回的實例是萬年不變的,無論誰去調用,都返回同一個類的實例,而new static()則是由調用者決定的
// new self()和new static()的區別 https://www.cnblogs.com/shizqiang/p/6277091.html
// ...$args 可變數量的參數 https://www.jb51.net/article/112664.htm
trait SingletonT {
private static $instance;
static function getInstance(...$args){
if(!isset(self::$instance)){
self::$instance = new static(...$args);
}
return self::$instance;
}
}
class Test{
use SingletonT;
public $name;
public function set($name){
$this->name = $name;
}
}
$obj1 = Test::getInstance();
$obj2 = Test::getInstance();
$obj1->set("dai");
$obj2->set("yuanpei");
echo $obj1->name; // 輸出結果 yuanpei
echo $obj2->name; // 輸出結果 yuanpei