2008-08-25 105 views
35

假設我正在寫一個本意爲單例的PHP(> = 5.0)類。我讀過的所有文檔都聲明使類構造函數是私有的,所以不能直接實例化類。在PHP5類中,何時調用私有構造函數?

所以,如果我有這樣的事情:

class SillyDB 
{ 
    private function __construct() 
    { 

    } 

    public static function getConnection() 
    { 

    } 
} 

是否有地方__construct()不是,如果我做的是類本身內部的

new SillyDB() 

呼叫被稱爲其他任何情況下?

爲什麼我允許從內部實例化SillyDB呢?

回答

61

__construct()只有在您從包含私有構造函數的類的方法中調用它時纔會被調用。因此,對於你單身,你可能有一個方法,像這樣:

class DBConnection 
{ 
    private static $Connection = null; 

    public static function getConnection() 
    { 
     if(!isset(self::Connection)) 
     { 
     self::Connection = new DBConnection(); 
     } 
     return self::Connection; 
    } 

    private function __construct() 
    { 

    } 
} 

$dbConnection = DBConnection::getConnection(); 

的原因,你能夠/想從內部自身實例化類,這樣就可以進行檢查,以確保只有一個實例存在於任何給定的時間。畢竟,這是一個單身人士的重點。使用Singleton進行數據庫連接可確保您的應用程序一次不會建立大量數據庫連接。

0

有點挑揀:爲了完整性,你可能會把聲明爲final,因爲你不想讓某人繼承這個類並實現它自己的公共構造函數。

(原諒我,如果編譯器捕獲一個私有構造函數的壓倒一切的,但我不認爲它)

+2

這是一條評論,而不是答案,但好點 – 2014-06-24 11:36:15

2

測試代碼,馬克,讓我知道你發現什麼。

編輯:此外,在這種特殊情況下,我不知道爲什麼你需要關注防止一個人從繼承。如果某人有權訪問您的PHP代碼以對其進行子類化,那麼他們也可以訪問您的代碼來複制它,並將訪問修飾符更改爲他們(出於任何原因)找到合適的內容。

Singleton在這種情況下的實際用處是,通過使用它,可以確保您始終對給定的HTTP請求使用相同的數據庫連接。它完成了這一點。其他的東西(使用final和私有構造函數)從理論角度是有用的,並且知道你是否想向其他程序員分發API質量代碼更有用,但在這個特例中,所有關鍵字正在做的是將字節添加到您的類文件的大小。

6

這裏是一個非常簡單的單,只是產生一個日期/時間字符串:

class TheDate 
{ 
    private static $DateInstance = null; 
    private $dateVal; 

    public static function getDateInstance() 
    { 
     if(!isset(self::$DateInstance)) 
     { 
      self::$DateInstance = new TheDate(); 
     } 

     return self::$DateInstance; 
    } 

    public static function getDateVal() 
    { 
     return self::$DateInstance->dateVal; 
    } 

    private function __construct() 
    { 
     $this->dateVal = strftime("%Y-%m-%d %H:%M:%S"); 
    } 
} 

做這樣的事情顯然是讓我同日一遍又一遍:

$date1 = TheDate::getDateInstance(); 
echo $date1->getDateVal() . "<br />"; 

$date2 = TheDate::getDateInstance(); 
echo $date2->getDateVal() . "<br />"; 

而且這樣做沒有按不會產生任何錯誤:

class NewDate extends TheDate 
{ 
    public function __construct() 
    { 

    } 
} 
4

好的,我跑了一些我自己的測試。

  • 如果不聲明在子類自己的構造函數,試圖實例就會拋出一個致命的錯誤,因爲它試圖調用父類的構造。
  • 在數據庫連接的情況下,當你大概返回(在PHP中,無論如何)一個mysqli實例或由mysql_connect()函數返回的資源(或某些其他RDBMS的其他鏈接),只要你標記這個實例是私有的,沒有任何人對它進行子類化和篡改鏈接的威脅。
  • 正如我之前提到的,如果有人真的想重寫你的行爲並建立多重聯繫,他們可以通過編寫一個新的類來完成。
相關問題