一步步編寫PHP的Framework(七)

來源:互聯網
上載者:User

 

之前我們在入口檔案就直接調用了Route::run(),這樣做有不有什麼問題呢?

答案是有的!

有時候在進行路由之前和之後需要進行一些額外的處理,如果按照之前在入口檔案直接調用Route::run()的話,那麼這些處理過程只能寫在入口檔案中,但是入口檔案本不應該做這樣的事情,那麼我們該怎麼樣來解決這個問題呢?

我們引入一個前端控制器的概念,它相當於一個總控,所有外部的請求都在它的控制範圍內,那麼這些額外的處理是不是就可以放在這個控制器中了呢!!

好,我們現在先修改一下入口檔案:

01 <?php
02 defined('APP_PATH') define('APP_PATH',dirname(__FILE__) . '/..');
03 defined('FRAMEWORK_PATH') define('FRAMEWORK_PATH',APP_PATH . '/Library/Test');
04 defined('MODULES_PATH') define('MODULES_PATH',APP_PATH . '/UserApps/Modules');
05 defined('CONFIGS_PATH') define('CONFIGS_PATH',APP_PATH . '/UserApps/Configs');
06 include FRAMEWORK_PATH . '/function.php';
07 C(Config::factory(Config::PHP)); //寫入配置資訊
08 include FRAMEWORK_PATH . '/FrontController.php';
09 $frontController = FrontController::getInstance();
10 $frontController->run();

 

這段代碼實際上修改的內容不多,也就修改了:

1 include FRAMEWORK_PATH . '/FrontController.php';
2 $frontController = FrontController::getInstance();
3 $frontController->run();

這段代碼首先include了前端控制器這個檔案,然後執行個體化了前端控制器,然後調用前端控制器這個類的run方法。

為什麼不直接使用$frontController = new FrontController()?

如果你把握後面的代碼下載後運行會發現,這樣會報錯,為什麼呢?

這兒我需要介紹另外一個概念:單例模式。

單例模式就是在整個程式運行過程中只有一個執行個體,比如資料庫的串連,即使有很多類,但是可能這些類都公用資料庫的串連,那麼資料庫的串連就是單例的。

為什麼要使用單例呢?

大家可以想一下,前端控制器控制整個程式的運行,那麼它的確是不應該有多份的,是不是?

 為了保證是單例的,所以我們一般使用一個靜態方法(getInstance)來執行個體化它,為了防止使用者直接new和複製一個對象,我們需要將__construct和__clone設定為私人。

01 <?php
02 class Test {
03     private static $_instance = null;
04     private function __construct() {}
05     private function __clone() {}
06     public static function getInstance() {
07         if(null === self::$_instance) {
08             self::$_instance = new Test();
09             echo '1';
10         }
11         return self::$_instance;
12     }
13 }
14  
15 $test = Test::getInstance();
16 $test2 = Test::getInstance();

 

如果執行這段代碼,會發現只輸出了一個1,說明執行個體化只執行了一次。

說了這麼多,大家應該都應該懂了吧,那就直接貼出前端控制器的代碼吧:

01 <?php
02 class FrontController {
03     private static $_instance = null;
04     private function __construct() {}
05     private function __clone() {}
06     public static function getInstance() {
07         if(!(self::$_instance instanceof self)) {
08             self::$_instance = new FrontController();
09         }
10         return self::$_instance;
11     }
12     public function run() {
13         Route::run();
14     }
15 }

當然,前端控制器中我是使用了instanceof來判定的,其實也可以直接用null === self::$_instance來判定。

 

這段代碼很簡單,實際上就把Route::run()轉移到FrontController了,其他的都沒有什麼變化。

大家可能注意到了,入口檔案的內容還是太多了,為什麼不能把入口檔案的東西遷移到FrontController呢,那麼那些可以遷移到FrontController呢,首先是定義的常量,其實只要使用者定義APP_PATH即可,其他的常量都可以由架構預設,其次是設定檔的寫入,這種內容架構完全可以自己搞定,所以,入口檔案的代碼變成了這樣:

1 <?php
2 defined('APP_PATH') define('APP_PATH',dirname(__FILE__) . '/..');
3 defined('FRAMEWORK_PATH') define('FRAMEWORK_PATH',APP_PATH . '/Library/Test');
4 include FRAMEWORK_PATH . '/FrontController.php';
5 $frontController = FrontController::getInstance();
6 $frontController->run();

我在此處留下了FRAMEWORK_PATH,是因為我要引用架構的檔案,其實也不定義FRMAEWORK_PATH,而改用include APP_PATH . '/Library/Test/FrontController.php'。

 

同樣,FrontController的代碼也發生了變化:

01 <?php
02 defined('APP_PATH')  exit('未定義APP_PATH');
03 defined('FRAMEWORK_PATH') define('FRAMEWORK_PATH',APP_PATH . '/Library/Test');
04 defined('MODULES_PATH') define('MODULES_PATH',APP_PATH . '/UserApps/Modules');
05 defined('CONFIGS_PATH') define('CONFIGS_PATH',APP_PATH . '/UserApps/Configs');
06 include FRAMEWORK_PATH . '/function.php';
07 class FrontController {
08     private static $_instance = null;
09     private function __construct() {
10         C(Config::factory(Config::PHP)); //寫入配置資訊
11     }
12     private function __clone() {}
13     public static function getInstance() {
14         if(!(self::$_instance instanceof self)) {
15             self::$_instance = new FrontController();
16         }
17         return self::$_instance;
18     }
19     public function run() {
20         Route::run();
21     }
22 }

首先,這個檔案判定是否定義了APP_PATH,由於這個常量非常重要,其他路徑都依靠它,所以使用者如果不指定,程式就需要停止。其他的常量如果沒有定義,那麼就定義它,這個很簡單。

 設定檔寫到了建構函式中了,因為不管getInstance調用多少次,建構函式只會被調用1次,而設定檔剛好也只需要寫入一次。



相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。