参考Thinkphp3.2的代码,在之前的框架开发中又发现了一些问题。所以在这里又重构了一次代码。因为一开始没有使用到控制器,所以没有发现之前的写法有很大的问题。
具体文件如下图:
这里面Dphp.php文件其实就是index.php入口文件主要载入的一个文件,这个文件主要是用来配置一些服务器的常量的。
Dphp.php
<?
define('DPHP_PATH',__DIR__.'/'); //核心文件根路径
define('PROJECT_PATH',dirname($_SERVER['SCRIPT_FILENAME']).'/'); //项目根路径
define('APP_PATH',PROJECT_PATH.'app/');//应用目录
define('CORE_PATH',realpath(DPHP_PATH.'core').'/'); //核心库文件
define('CONF_PATH',realpath(DPHP_PATH.'conf').'/'); //初始化变量配置文件
define('TEMPLATE_PATH',realpath(DPHP_PATH.'template').'/'); //模板库文件
define('RUNTIME_PATH',realpath(DPHP_PATH.'runtime').'/'); //运行文件
//加载核心类
require_once CORE_PATH.'dphp.php';
//开始
\Dphp\core\dphp::start();
然后,配置完常量后就可以非常方便的使用关于文件的路径问题了。之后就是载入dphp.php文件的start静态方法。
dphp.php
<?php
namespace Dphp\core;
class dphp{
//类映射
private static $_map = array();
//实例化对象
private static $_instance = array();
public static function start(){
// 注册AUTOLOAD方法
spl_autoload_register('\Dphp\core\dphp::autoload');
app::run();
}
//类自动加载
public static function autoload($class){
#echo '<br/>'.__FILE__.'<br/>';
echo '<br/>'.'自动加载了'.$class.'<br/>';
@include_once $class.'.php';
}
//取得对象实例
static public function instance($class,$method=''){
$identify = $class.$method;
if(!isset(self::$_instance[$identify])){
if(class_exists($class)){
$o = new $class();
if(!empty($method) && method_exists($o,$method)){
self::$_instance[$identify] = call_user_func(array(&$o,$method));
}else{
self::$_instance[$identify] = $o;
}
}else{
//错误处理 do something
}
}
return self::$_instance[$identify];
}
}
这里面有两个参数用来保存方法和对象,然后就是类的自动载入一系列的常用函数。在start里面用一个app::run的静态方法,所以之后就是转到应用的类里面执行。
app.php
namespace Dphp\core;
class app{
static public function run(){
//url
dispatcher::dispatch();
//执行相应目录下的模块-控制器-方法
app::exec();
}
static public function exec(){
$class = 'app\\'.MODULE_NAME.'\\controller\\'.CONTROLLER_NAME;
echo '<br/>';
echo $class;
echo '<br/>';
echo '准备创建控制器了';
echo '<br/>';
//检测是否存在当前的类
if(class_exists($class)) {
$c = new $class();
echo '创建控制器了';
}
}
}
上面的start函数会执行路由解析函数,用来判断应该访问什么文件。
dispatcher.php
<?php
/**
* Created by PhpStorm.
* User: DMF
* Date: 2017/9/18
* Time: 19:15
*/
namespace Dphp\core;
class dispatcher{
//url映射到控制器
static public function dispatch(){
@$path_info = $_SERVER['PATH_INFO'];
//路径判断是否为空
if(empty($path_info)){
$varModule = 'home';
$varController = 'index';
$varAction = 'index';
$urlCase = '';
echo '0';
}else{
echo '1';
//去除首尾的'/'
$path_info = trim($path_info,'/');
//以/为分隔符,分配给数组
$url = explode('/',$path_info);
$varModule = $url[0];
$varController = $url[1];
$varAction = $url[2];
//$urlCase = ;
}
//定义全局变量
define('MODULE_NAME',$varModule);
define('CONTROLLER_NAME',$varController);
define('ACTION_NAME',$varAction);
}
}
这里面使用$_SERVER['PATH_INFO']来获取当前的m,v,c的名字,然后再使用define将值传递出去。这样子我们就获得了一个路径了。然后就是app里面继续执行exec函数。这个函数就是要new出一个控制器,这里默认是index控制器。
index.php控制器
<?php
/**
* Created by PhpStorm.
* User: DMF
* Date: 2017/9/20
* Time: 21:42
*/
namespace app\home\controller;
class index extends \Dphp\core\controller{
public function __construct()
{
parent::__construct();
echo '来到index控制器'.'<br/>';
$this->display();
}
}
在app::exec函数里我们采用new 命名空间的形式,所以这里面的命名空间要符合应用文件夹里面的路径,不然会找不到文件的。
之后继承了基本控制器Controller就能够使用smarty模板来输出网页信息了。
控制器的制作就完成了。
效果如下:
2017.9.25
在继续开发框架的过程中,我发现原来我一开始写的控制器存在着一个非常大的问题。那就是无法访问控制器的其它方法函数,因为我的演示是在构造函数里面所以一开始没有发现这个问题。之后,在了解thinkphp的代码的时候,发现可以使用反射的方法来实现函数的调用。
在这我新添加了一个route类。
<?php
/**
* Created by PhpStorm.
* User: DMF
* Date: 2017/9/25
* Time: 14:06
*/
namespace Dphp\core;
class route
{
//检查路由信息
public static function check(){
self::invoke(ACTION_NAME,'app\\'.MODULE_NAME.'\\controller\\'.CONTROLLER_NAME);
}
//反射函数
public static function invoke($name,$className){
//创建反射方法对象
$reflect = new \ReflectionMethod($className,$name);
//获取当前方法的参数
$params = $reflect->getParameters();
$args = array();
//获取要调用方法的实例对象
$obj = \Dphp\core\dphp::instance($className);
//遍历参数
foreach ($params as $param) {
$args[] = $param->getDefaultValue();
}
if(empty($args)){
return $reflect->invoke($obj);
}
else{
return $reflect->invokeArgs($obj,$args);
}
}
}
这个route类就是用来实现函数的调用的,不然只是获取到mvc的名称却无法使用。这个check函数可以放在路由转发的dispatcher 类里面的dispatch方法。
//路由检测
route::check();
这样子才算真正的实现完成一个控制器。