啥是註冊表模式?其實很簡單!
註冊表的作用是提供系統層級的物件存取功能。我們在編碼時通常把「全域變數是不好的」當作信條。不過,凡事都有兩面性,全局性的資料存取非常具有吸引力。
問題來了:
大多係統都分為幾個層,每個層都只透過事先定義好的通道和相鄰的層交流。對層的分享使程式變得靈活,替換或修改每個層可以最小化對系統其他部分的影響。但當你需要在一個層中獲取不相鄰另一個層所需的資訊時,該如何?
方案一:透過系統的層之間的聯繫將上下文資訊從一個對象傳遞給另一個需要的對象:在系統中把這些資訊從一個對象傳遞到另一個對象,從一個負責處理請求的控制器物件傳遞到業務邏輯層的對象,再傳遞到負責和資料庫對話的對象。當然也可以傳遞ApplicationHelper對象,或是特定的Context對象。
方案二:必須修改所有物件的接口,判斷上下文物件是否是它們需要的。很顯然,有時候這種方案會破壞鬆散耦合。
方案三:透過登錄模式。註冊表類別提供靜態方法(或單例物件的實例化方法)來讓其他物件存取其中的資料(通常是物件)。整個系統中的每個物件都可以存取這些資料物件。
在實現之前先考慮一下PHP的作用域:
作用域通常用於描述程式碼中物件或值的可見程序,變數的生命週期可以用時間來衡量,變數作用域有3個層級。
一、HTTP請求作用域
指一個HTTP請求從開始到結束的週期。
二、會話作用域
PHP內建了會話變數的支援。在一次請求結束後,會話變數會被序列化並儲存到檔案系統或資料庫中,然後在下一個請求開始時取回。存放在cookie中的會話ID和透過查詢字串傳遞的會話ID被用來追蹤該會話的擁有者。因此,你可以認為某些變數擁有會話層級的作用域。利用這一點,可以在幾次請求之間存放對象,保存使用者存取的踪跡到資料庫中。當然,要小心避免持有同一個物件的不同版本,因此當你把一個會話物件存到資料庫時,需要考慮使用一定的鎖定策略。
三、應用程式作用域
在其他語言中,特別是JAVA,擁有快取池,即「應用程式作用域」的概念。記憶體中的變數可以被程式中的所有物件實例存取。 PHP沒有這樣的功能,但是在大規模的應用中,為了存取配置變量,存取應用程式層級的資料是很有用的。
下面就用註冊表實現這三個作用域,類別圖如下:
<?php namespace woo\base; require_once( "woo/controller/AppController.php"); abstract class Registry { abstract protected function get( $key ); abstract protected function set( $key, $val ); } class RequestRegistry extends Registry { private $values = array(); private static $instance; private function __construct() {} static function instance() { if ( ! isset(self::$instance) ) { self::$instance = new self(); } return self::$instance; } protected function get( $key ) { if ( isset( $this->values[$key] ) ) { return $this->values[$key]; } return null; } protected function set( $key, $val ) { $this->values[$key] = $val; } static function getRequest() { return self::instance()->get('request'); } static function setRequest( \woo\controller\Request $request ) { return self::instance()->set('request', $request ); } } class SessionRegistry extends Registry { private static $instance; private function __construct() { session_start(); } static function instance() { if ( ! isset(self::$instance) ) { self::$instance = new self(); } return self::$instance; } protected function get( $key ) { if ( isset( $_SESSION[__CLASS__][$key] ) ) { return $_SESSION[__CLASS__][$key]; } return null; } protected function set( $key, $val ) { $_SESSION[__CLASS__][$key] = $val; } function setComplex( Complex $complex ) { self::instance()->set('complex', $complex); } function getComplex( ) { return self::instance()->get('complex'); } } class ApplicationRegistry extends Registry { private static $instance; private $freezedir = "/tmp/data"; private $values = array(); private $mtimes = array(); private function __construct() { } static function instance() { if ( ! isset(self::$instance) ) { self::$instance = new self(); } return self::$instance; } protected function get( $key ) { $path = $this->freezedir . DIRECTORY_SEPARATOR . $key; if ( file_exists( $path ) ) { clearstatcache(); $mtime=filemtime( $path ); if ( ! isset($this->mtimes[$key] ) ) { $this->mtimes[$key]=0; } if ( $mtime > $this->mtimes[$key] ) { $data = file_get_contents( $path ); $this->mtimes[$key]=$mtime; return ($this->values[$key]=unserialize( $data )); } } if ( isset( $this->values[$key] ) ) { return $this->values[$key]; } return null; } protected function set( $key, $val ) { $this->values[$key] = $val; $path = $this->freezedir . DIRECTORY_SEPARATOR . $key; file_put_contents( $path, serialize( $val ) ); $this->mtimes[$key]=time(); } static function getDSN() { return self::instance()->get('dsn'); } static function setDSN( $dsn ) { return self::instance()->set('dsn', $dsn); } static function setControllerMap( \woo\controller\ControllerMap $map ) { self::instance()->set( 'cmap', $map ); } static function getControllerMap() { return self::instance()->get( 'cmap' ); } static function appController() { $obj = self::instance(); if ( ! isset( $obj->appController ) ) { $cmap = $obj->getControllerMap(); $obj->appController = new \woo\controller\AppController( $cmap ); } return $obj->appController; } } //如果你安装了PHP的shm扩展,就可以使用该扩展中函数来实现应用程序注册表 class MemApplicationRegistry extends Registry { private static $instance; private $values=array(); private $id; const DSN=1; private function __construct() { $this->id = @shm_attach(55, 10000, 0600); if ( ! $this->id ) { throw new Exception("could not access shared memory"); } } static function instance() { if ( ! isset(self::$instance) ) { self::$instance = new self(); } return self::$instance; } protected function get( $key ) { return shm_get_var( $this->id, $key ); } protected function set( $key, $val ) { return shm_put_var( $this->id, $key, $val ); } static function getDSN() { return self::instance()->get(self::DSN); } static function setDSN( $dsn ) { return self::instance()->set(self::DSN, $dsn); } } ?>