1. 程式人生 > >php 的單例模式(一)

php 的單例模式(一)

  單例模式,就是保持一個物件只存在一個例項。並且為該唯一例項提供一個全域性訪問點(一般是一個靜態的getInstance方法),單例模式使用的地方很多,一般在資料庫操作物件日誌寫入物件全域性配置解析物件等用的比較多。

  他們的共同特徵我決定有以下3點:

1.只需要一個例項

2.不斷new多個例項會不斷增加資源的消耗

3.全域性呼叫的話會很便利

單例模式具備的三個關鍵點:

① 需要一個儲存類的唯一例項的靜態成員變數;

②建構函式和克隆函式必須宣告為私有的,防止外部程式new類從而失去單例模式的意義;

③必須提供一個訪問這個例項的公共的靜態方法(通常為getInstance方法),從而返回唯一例項的一個引用 。

  我們來寫一個例子來看一下,下面是一個日誌操作類:

class Logger{

      //首先,需要一個私有的靜態變數來儲存產生的物件例項
      private static $instance;

      //業務變數,儲存日誌寫入路徑
      private $logDir;

      //構造方法,注意必須也是私有的,不允許被外部例項化(即在外部被new)
      private function __construct(){
          //除錯輸出,測試物件被new的次數
          echo "new Logger instance \r\n";
          $logDir = sys_get_temp_dir(). DIRECTORY_SEPARATOR . "logs";
          if(!is_dir($logDir) || !file_exists($logDir)){
              @mkdir($logDir);
          }
          $this->logDir = $logDir;

      }

      //類唯一例項的全域性訪問點,用於判斷並返回物件例項,供外部呼叫
      public static function getInstance(){
          if(is_null(self::$instance)){
              $class = __CLASS__; //獲取本物件的型別,也可以用new self()方式
              self::$instance = new $class();
          }
          return self::$instance;
      }

      //過載__clone()方法,不允許物件對克隆
      public function __clone(){
          throw new Exception("Singleton Class Can Not Be Cloned");
      }

      //具體的業務方法,實際可以有很多方法
      public function logError($message){
          $logFile = $this->logDir . DIRECTORY_SEPARATOR . "error.log";
          error_log($message, 3, $logFile);
      }
  }

  //日誌呼叫
  $logger = Logger::getInstance();
  $logger->logError("An error occured");
  $logger->logError("Another error occured");

  //或者這樣呼叫
  Logger::getInstance()->logError("Still have error");
  Logger::getInstance()->logError("I should fix it");


這就是一個單例模式的一個簡單例子。

重點注意:單例濫用,單例模式相對來說比較好理解和實現,因此一旦認識到單例模式的好處,很可能什麼類都想寫成單例,因此在使用次模式之前一定要考慮之前博主說的3種情況,看是否真的有必要使用。