手把手編寫自己的PHP MVC框架實例教程

主要針對這篇轉載博文無法正常運行的bug修訂https://blog.csdn.net/chengshaolei2012/article/details/72675124
這篇博文的原始作者在http://www.awaimai.com/128.html#1MVC
不過我看了下上面那篇並沒有完全照搬,有些細節地方不同,比如他沒有用命名空間

1. 重定向

我只試了Apache,代碼改進

Options +Indexes +FollowSymLinks +ExecCGI
<IfModule mod_rewrite.c>
    # 打開Rerite功能
    RewriteEngine On

    # 如果請求的是真實存在的文件或目錄,直接訪問
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d

    # 如果訪問的文件或目錄不是真事存在,分發請求至 index.php
    RewriteRule . index.php
</IfModule>

2. 配置文件

這個地方錯的比較離譜,他把原作者的數組改成了常量,但是在其他文件中他用的還是數組,導致不能正常運行,參考這個轉載的https://blog.csdn.net/qq_35524813/article/details/52692257可以發現一些問題,數據庫配置。

<?php

//數據庫配置
/*
define('DB_NAME','study');
define('DB_USER','root');
define('DB_PASSWORD','root');
define('DB_HOST','localhost');
*/
$config['db']['host'] = 'localhost';
$config['db']['username'] = 'root';
$config['db']['password'] = 'root';
$config['db']['dbname'] = 'study';

//默認控制器和操作名
$config['defaultController']='Item';
$config['defaultAction']='index';

return $config;

3. 框架核心類

此處的問題是loadClass方法,自動加載類,調用子類會自動加載父類,但是前提是類文件的命名方式要一樣。他這裏改變了原作者的命名方式,基類命名方式爲XXX.class.php,普通類命名方式爲XXX.php,所以他的寫法導致基類沒有加載,我們可以改變命名規則,也可以像下面一樣把加載基類的代碼添進去。

<?php

//fast核心框架
class Fastphp{
	
	protected $_config=[];
	public function __construct($config){
		$this->_config=$config;
	}
	
	//運行程序
	public function run(){
		spl_autoload_register(array($this,'loadClass'));
		$this->setDbConfig();
		$this->setReporting();
		$this->removeMagicQuotes();
		$this->unregisterGlobals();
		$this->route();
	}
	
	//路由處理
	public function route(){
		$controllerName=$this->_config['defaultController'];
		$actionName=$this->_config['defaultAction'];
		$param=array();
		
		$url=$_SERVER['REQUEST_URI'];
		/*$_SERVER $_SERVER 是一個包含了諸如頭信息(header)、路徑(path)、以及腳本位置(script locations)等等信息的數組。這個數組中的項目由 Web 服務器創建。不能保證每個服務器都提供全部項目;服務器可能會忽略一些,或者提供一些沒有在這裏列舉出來的項目。$_SERVER["REQUEST_URI"]  當前腳本路徑,根目錄之後的目錄。$_SERVER["SCRIPT_NAME"]  當前腳本的路徑。這在頁面需要指向自己時非常有用。
$_SERVER["PHP_SELF"]  當前正在執行腳本的文件名。$_SERVER["SCRIPT_FILENAME"]  當前執行腳本的絕對路徑。
		*/
		
		//清除?之後的內容
		$position=strpos($url,'?');//strpos() f函數查找字符串在另一字符串中第一次出現的位置(區分大小寫),如果沒有找到字符串則返回 FALSE。
		$url=$position===false?$url:substr($url,0,$position);
		
		//刪除前後的/斜槓
		$url=trim($url,'/');
		
		if($url){
			
			//使用/斜槓分割字符串,並保存在數組中
			$urlArray=explode('/',$url);
			
			//刪除空的數組元素
			$urlArray=array_filter($urlArray);//array_filter — 用回調函數過濾數組中的單元如果沒有提供 callback 函數, 將刪除 array 中所有等值爲 FALSE 的條目。
			
			//獲取控制器名
			$controllerName=ucfirst($urlArray[0]);//ucfirst() 函數把字符串中的首字符轉換爲大寫。
			
			//獲取動作名
			array_shift($urlArray);//array_shift() 函數用於刪除數組中的第一個元素,並返回被刪除的元素,如果數組爲空則返回 NULL。
			$actionName=$urlArray?$urlArray[0]:$actionName;
			
			//獲取URL參數
			array_shift($urlArray);
			$param=$urlArray?$urlArray:array();
			
			//判斷控制器和方法是否存在
			$controller=$controllerName.'Controller';
			if(!class_exists($controller)){//class_exists — 檢查類是否已定義,名字的匹配是不分區大小寫的。
				exit($controller.'控制器不存在');
			}
			if(!method_exists($controller,$actionName)){//method_exists,檢查類的方法是否存在於指定的 object中。
				exit($actionName.'方法不存在');
			}
			
			/*如果控制器和操作方法存在,則實例化控制器,因爲控制器對象裏面還會用到控制器名和方法名,所以實例化的時候把他們倆的名稱也傳進去,結合Controller基類一起
			*/
			$dispatch=new $controller($controllerName,$actionName);
			/* $dispatch保存控制器實例化後的對象,我們就可以調用它的方法,也可以像方法中傳入參數,以下等同於:$dispatch->$actionName($param); */
			call_user_func_array(array($dispatch,$actionName),$param);//call_user_func_array — 調用回調函數,並把一個數組參數作爲回調函數的參數
		}
			
	}
	
	//檢測開發環境
	public function setReporting(){
		if(APP_DEBUG===true){
			error_reporting(E_ALL);//error_reporting — 設置報告何種 PHP 錯誤,E_ALL報告所有 PHP 錯誤,ini_set('error_reporting', E_ALL);和 error_reporting(E_ALL); 一樣
			ini_set('display_errors','On');
		}else{
			error_reporting(E_ALL);
			ini_set('display_errors','Off');//設置配置文件,關閉錯誤顯示
			ini_set('log_errors','On');//錯誤日誌開啓
			//ini_set('error_log', RUNTIME_PATH. 'logs/error.log');
		}
	}
	
	//刪除敏感字符
	public function stripSlashesDeep($value){
		$value=is_array($value)?array_map(array($this,'stripSlashesDeep'),$value):stripslashes($value);//array_map — 爲數組的每個元素應用回調函數,stripslashes 去掉反斜槓,addslashes() 加反斜杆,爲了防止雙層轉義請使用get_magic_quotes_gpc() 進行檢測
		return $value;
	}
	
	//檢測敏感字符並刪除
	public function removeMagicQuotes(){
		if(get_magic_quotes_gpc()){
			$_GET=isset($_GET)?$this->stripSlashesDeep($_GET):'';// isset 檢測變量是否已設置並且非 NULL
			$_POST=isset($_POST)?$this->stripSlashesDeep($_POST):'';
			$_COOKIE=isset($_COOKIE)?$this->stripSlashesDeep($_COOKIE):'';
			$_SESSION=isset($_SESSION)?$this->stripSlashesDeep($_SESSION):'';
		}
	}
	
	/* 檢測自定義全局變量並移除。因爲register_globals已經棄用,如果已經棄用的register_globals指令被設置爲On,那麼局部變量也將在腳本的全局作用域中可用。例如,$_POST['foo']也將以$foo的形式存在,這樣寫是不好地地道道的實現,會影響代碼中其他變量。相關信息,參考http://php.net/manual/zh/faq.using.php#faq.register-globals */
	public function unregisterGlobals(){
		if(ini_get('register_globals')){
			$array=array('_SESSION','_POST','_GET','_COOKIE','_REQUEST','_SERVER','_ENV','_FILES');
			foreach($array as $value){
				foreach($GLOBALS[$value] as $key=>$var){
					if($var === $GLOBALS[$key]){
						unset($GLOBALS[$key]);
					}
				}
			}
		}
	}
	
	//配置數據庫信息
	public function setDbConfig(){
		if($this->_config['db']){
			Model::$dbConfig=$this->_config['db'];
		}
	}
	
	//自動加載控制器和模型類
	public static function loadClass($class){
		
		$frameworks=__DIR__.'/'.$class.'.php';
		$controllers=APP_PATH.'application/controllers/'.$class.'.php';
		$models=APP_PATH.'application/models/'.$class.'.php';
		$modelsclass=APP_PATH.'application/models/'.$class.'.class.php';
		$controllersclass=APP_PATH.'application/controllers/'.$class.'.class.php';
		$views=APP_PATH.'application/views/'.$class.'.class.php';
		if(file_exists($frameworks)){//file_exists — 檢查文件或目錄是否存在
			//加載框架核心類
			include($frameworks);
		}elseif(file_exists($controllers)){
			//加載應用控制器類
			include($controllers);
		}elseif(file_exists($models)){
			//加載應用模型類
			include($models);
		}elseif(file_exists($modelsclass)){
			//加載應用模型基類
			include($modelsclass);
		}elseif(file_exists($controllersclass)){
			//加載應用控制器基類
			include($controllersclass);
		}elseif(file_exists($views)){
			//加載視圖基類
			include($views);
		}else{
			echo '錯誤處理代碼!';
		}
		
	}

}
?>

其他代碼都沒有問題了,就這樣吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章