手把手编写自己的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 '错误处理代码!';
		}
		
	}

}
?>

其他代码都没有问题了,就这样吧。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值