一、什麼是PHP單例模式
單例模式是一種常用的軟件設計模式,它保證某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。單例模式的實現很簡單,只需要將類的構造方法設為私有,這樣該類就無法在外部被實例化,再創建一個靜態的方法作為實例化該類的入口。
class Singleton
{
private static $instance = null;
private function __construct()
{
}
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
}
上面代碼中,$instance是當前類的實例,使用getInstance()方法得到實例,若還沒有存在實例,new一個實例然後返回。由於每次返回的均為同一實例,故稱單例。PS:這裡我們採用了static來實現一些靜態綁定的操作,讓單例類適用於面向對象和繼承特性。如果你對於static關鍵字不熟悉,建議先查看與學習。
二、PHP單例模式的優點
單例模式具有以下優點:
1. 節省內存空間: 如果全局變量在某個時刻不再使用,但其仍然佔據着內存空間,如果這個全局變量被賦值為NULL或者是Session中某個變量刪除了這個變量,此時它在內存中佔用的空間並沒有被釋放。而單例模式的實例在全局只需保存一次,對於頻繁使用的對象可以大大節省內存空間。
2. 簡化調用: 單例模式使得代碼調用更加方便,而不必擔心實例化問題。單例模式的每個請求獲得同一個對象實例,節省了資源。
3. 保證數據一致性: 在程序運行期間,單例模式可以保證內存中只有一個對象,可以很好地控制實例化次數,從而保證數據的一致性。
三、PHP單例模式的缺點
單例模式雖然便捷,但有時會給我們帶來一些問題:
1. 開銷大: 大部分情況下,單例模式的性能要比普通實例化的開銷要大,這主要是由於在調用其getInstance()方法時,必須先檢查是否存在一個實例並進行實例化,從而讓實例化過程變慢。
2. 修改困難: 在一個系統中,單例的優勢變得明顯,但是當一個系統需要許多單例類時,修改成本會變得更高。因為所有使用該單例類的代碼都需要改動。
3. 不利於測試: 單例模式跟全局變量很像,都是不受控制的!由於單例模式限制了構造函數(如果Singleton類被禁止以常規方式進行實例化),這使得單例模式變得難以測試。它們很難被mock或者替換為另一個因為很難保證測試是否與實際代碼可以正常運行,這使得測試變得困難。
四、什麼時候適合用PHP單例模式
1. 數據庫連接: PHP的數據庫連接需要較長時間,使用單例模式可以減少連接時間和不必要的流量。
2. 日誌文件: 多人開發過程中,如果頻繁輸出同一個文件,會導致系統不斷地鎖定和釋放文件,造成很大的系統性能消耗。使用單例模式可以避免多次打開同一文件。
3. 只需一個對象實例: 如果在程序中只需要一個對象,那麼使用單例模式可以減小開銷。
五、PHP單例模式的應用場景
PHP單例模式廣泛用於數據處理和資源管理方面,這裡我們來介紹兩個典型的應用場景。
1、數據庫連接池
為了避免頻繁開啟數據庫連接和釋放數據庫連接,很多開發人員選擇使用數據庫連接池來管理數據庫連接。連接池是一種典型的單例模式。在連接池中,只有一個對象實例,可以重複使用該實例。
class DatabaseConnection
{
private static $instance = null;
private $connection = null;
private function __construct()
{
$this->connection = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
}
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
public function getConnection()
{
return $this->connection;
}
}
上面代碼中,getInstance()方法用於獲取DatabaseConnection類的唯一實例,getConnection()方法用於獲取數據庫連接對象。
2、配置信息
PHP的配置信息經常需要被修改,所以使用單例模式將配置信息存儲在內存中,並注入到應用程序中,可以方便地在應用程序中使用配置信息。
class Config
{
private static $instance = null;
private $config = [];
private function __construct()
{
$this->config = parse_ini_file('config.ini');
}
public static function getInstance()
{
if (null === static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
public function get($key)
{
if (isset($this->config[$key])) {
return $this->config[$key];
}
return false;
}
}
上面代碼中,getInstance()方法用於獲取Config類的唯一實例,get()方法用於獲取配置信息。
六、小結
相對於常規對象生成方式,在某些場合,單例模式的優點尤為突出。PHP單例模式解決了一些常見問題,但亦會帶來新問題,需細心思考,做出最實用、高效的代碼設計。
全文源碼已放置於Github倉庫,歡迎批評指正!
原創文章,作者:QOALP,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/332845.html