一步步編寫簡單的PHP的Framework(四)

 班級聚會剛回來,繼續寫這個文章吧!!php

      上一篇文章我提了一個問題,怎麼實現自動載入一個類呢?框架

       實際上PHP已經有相應的機制能夠實現這個功能了,這個機制就是autoload,它會在試圖使用還沒有被定義的類時自動調用。函數

       如今咱們能夠在Route.php中的開頭定義autoload函數(固然,這樣是不規範的,可是爲了簡單,先這麼作)。測試

        咱們如今的自動導入須要導入兩類文件,一類是框架類文件,另一類是用戶應用模塊的類文件,爲了簡化代碼,能夠假設框架的全部文件都存放在/Library/Test目錄下面,用戶類文件都存放在/UserApps/Modules目錄下面,而且只會在Controllers,Models,Helpers這三個目錄下面,而且這幾個目錄下面沒有子目錄。ui

         對於這個自動導入的函數,它須要首先嚐試導入框架類文件,若是該文件不存在,說明是用戶類文件,而後再嘗試導入用戶類文件,若是是,那麼include它。.net

         注意:設計

             因爲要頻繁使用UserApps/Modules這個目錄,因此我定義了一個MODULES_PATH這個常量;code

       

function __autoload($className) {
	$frameworkFileName = FRAMEWORK_PATH . '/' . $className . '.php';
	if(is_file($frameworkFileName)) {
		include $frameworkFileName;
	} else {
		//用戶類文件
		$controllerFileName = MODULES_PATH . '/Controllers/' . $className . '.php';
		if(is_file($controllerFileName)) {
			include $controllerFileName;
		} else {
			$modelFileName = MODULES_PATH . '/Models/' . $className . '.php';
			if(is_file($modelFileName)) {
				include $modelFileName;
			} else {
				$helperFileName = MODULES_PATH . '/Helpers/' . $className . '.php';
				if(is_file($helperFileName)) {
					include $helperFileName;
				} else {
					throw new Exception("class not found");
				}
			}
		}
	}
}

 

 

           當你把這個函數寫完以後,能夠在以前已經寫好的IndexController.php中去測試一下,好比在和IndexController同一目錄下面創建一個文件Test.php,文件代碼以下:blog

 

<?php
class Test {
      public function test() {
         echo 'Test';
      }
}

而後在IndexController.php中使用以下:ip

 

 

<?php
class IndexController {
	public function index() {
		$test = new Test();
                $test->test();
	}
}

若是出現Test,那麼恭喜你,自動導入成功了!!

 

             如今再考慮一下,若是針對一個很複雜的項目,使用這種方式來自動導入,有什麼問題嗎?

             其實問題是比較嚴重的,首先對於框架的文件,咱們不可能將全部文件都存放在一個目錄下面,這樣當文件多了以後就檢索就麻煩了;對於用戶類文件,好比控制器的文件,咱們不可能將它所有存放在一個目錄下面,咱們須要按照模塊切分目錄等。若是用__autoload來實現的話,這個函數的代碼量就太大了,並且若是有一個地方的修改那麼就可能牽一髮而動全身,這樣對於項目的維護是很不利的。

             那麼咱們怎麼解決這個問題呢?

             方法一:

                 咱們定義不少輔助函數,好比導入框架文件,咱們定義一個frameworkAutoloadHelper,對於用戶文件定義一個userAutoloadHelper,而後將業務邏輯存放在這兩個函數中,最後在__autoload中調用這兩個函數便可,當用戶功能須要修改的時候,代碼維護性就好一些了;

             方法2:

                 在SPL中已經定義了一個spl_autoload_register,可使用這個來說自動導入的功能分攤到多個類中,並且還能夠將自動導入的控制權交給用戶,這對於框架來講是比較重要的,因此,我推薦使用這種方式。

                  具體這種方式怎麼實現,讀者能夠本身查查PHP手冊,也能夠查看我寫的Toper框架的相應實現,具體實現類在/Library/Toper/Loader.class.php。

           當咱們使用了spl_autoload_register以後,是否是一切就高枕無憂了?

            其實不是,咱們如今能夠想一下是否能夠去除自動導入呢,由於當業務邏輯很複雜而且自動導入設計的又不是特別好的時候,自動導入的效率就不是很高了!!

             不用自動導入,難道仍是使用include?No。

             你們都知道include,include_once,require,require_once的區別吧!!

             include和require每次調用都會包含這個文件,include_once和require_once只會導入一次,include若是包含了一個不存在的文件,只會拋出警告,程序會繼續執行,而require會中止執行,因此這四個函數我比較建議使用require_once,可是很遺憾,這個函數效率很低,由於它要考慮的東西太多了!!

               PS:使用這四個函數的時候,最好使用絕對路徑,這樣效率要高一些;

              若是咱們使用require,那麼效率會高不少,可是若是使用require怎麼實現require_once的功能呢?

              我給你們提供一個思路,使用static變量:

 

<?php
function testRequireOnce($file) {
      static $_config = array();
      if(!isset($_config[$file])) {
         require $file;
         $_config[$file] = $file;
      }
}

 

            固然,還可使用class_exists來斷定。

             此次的代碼能夠點此下載

相關文章
相關標籤/搜索