1 框架目录

1.1 创建目录结构

1561428443831.png

1.2 文件分类存放

1561429370394.png

将文件存放到不同的目录以后,由于类文件地址发生了变化,所以无法完成自动加载类,那么今天的主要任务就是围绕如何实现类的自动加载展开。

由于每次都请求入口文件,所以”.“表示入口文件所在的目录

2 添加命名空间

通过文件目录地址做命名空间,这样获取了命名空间就能知道文件存放的地址。

Model.class.php

1
2
3
namespace Core;
class Model {
  ...

MyPDO.class.php

1
2
3
namespace Core;
class MyPDO{
  ...

ProductsModel.class.php

1
2
3
4
5
<?php
namespace Model;
//products模型用来操作products表
class ProductsModel extends Model{
  ...

ProductsController.class.php

1
2
3
4
5
<?php
namespace Controller\Admin;
//商品模块
class ProductsController {
  ...

3 框架类实现

3.1 定义路径常量

由于文件路径使用频率很高,而且路径比较长,所以将固定不变的路径定义成路径常量

知识点

1
2
1getcwd():入口文件的绝对路径
2、windows下默认的目录分隔符是`\`,Linux下默认的目录分隔符是`/`。DIRECTORY_SEPARATOR常量根据不同的操作系统返回不同的目录分隔符。

代码实现

在Core文件夹下创建Framework.class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
private static function initConst(){
   define('DS', DIRECTORY_SEPARATOR);  //定义目录分隔符
   define('ROOT_PATH', getcwd().DS);  //入口文件所在的目录
   define('APP_PATH', ROOT_PATH.'Application'.DS);   //application目录
   define('CONFIG_PATH', APP_PATH.'Config'.DS);
   define('CONTROLLER_PATH', APP_PATH.'Controller'.DS);
   define('MODEL_PATH', APP_PATH.'Model'.DS);
   define('VIEW_PATH', APP_PATH.'View'.DS);
   define('FRAMEWORK_PATH', ROOT_PATH.'Framework'.DS);
   define('CORE_PATH', FRAMEWORK_PATH.'Core'.DS);
   define('LIB_PATH', FRAMEWORK_PATH.'Lib'.DS);
   define('TRAITS_PATH', ROOT_PATH.'Traits'.DS);
}

3.2 引入配置文件

1、在config目录下创建config.php

1
2
3
4
5
6
7
8
9
10
11
<?php
return array(
   //数据库配置
   'database'=>array(),
   //应用程序配置
   'app'       =>array(
       'dp'    =>  'Admin',        //默认平台
       'dc'    =>  'Products',     //默认控制器
       'da'    =>  'list'          //默认方法
  ),
);

2、在框架类中引入配置文件

1
2
3
private static function initConfig(){
  $GLOBALS['config']=require CONFIG_PATH.'config.php';
}

思考:配置文件为什么不保存在常量中?

答:因为7.0之前,常量不能保存数组和对象。

3.3 确定路由

p:【platform】平台

c:【controller】控制器

a:【action】方法

1561431781576.png

1
2
3
4
5
6
7
8
9
10
11
12
13
private static function initRoutes(){
$p=$_GET['p']??$GLOBALS['config']['app']['dp'];
$c=$_GET['c']??$GLOBALS['config']['app']['dc'];
$a=$_GET['a']??$GLOBALS['config']['app']['da'];
$p=ucfirst(strtolower($p));
$c=ucfirst(strtolower($c)); //首字母大写
$a=strtolower($a); //转成小写
define('PLATFROM_NAME', $p); //平台名常量
define('CONTROLLER_NAME', $c); //控制器名常量
define('ACTION_NAME', $a); //方法名常量
define('__URL__', CONTROLLER_PATH.$p.DS); //当前请求控制器的目录地址
define('__VIEW__',VIEW_PATH.$p.DS); //当前视图的目录地址
}

3.4 自动加载类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static function initAutoLoad(){
spl_autoload_register(function($class_name){
$namespace= dirname($class_name); //命名空间
$class_name= basename($class_name); //类名
if(in_array($namespace, array('Core','Lib'))) //命名空间在Core和Lib下
$path= FRAMEWORK_PATH.$namespace.DS.$class_name.'.class.php';
elseif($namespace=='Model') //文件在Model下
$path=MODEL_PATH.$class_name.'.class.php';
elseif($namespace=='Traits') //文件在Traits下
$path=TRAITS_PATH.$class_name.'.class.php';
else //控制器
$path=CONTROLLER_PATH.PLATFROM_NAME.DS.$class_name.'.class.php';
if(file_exists($path) && is_file($path))
require $path;
});
}

3.5 请求分发

1
2
3
4
5
6
private static function initDispatch(){
$controller_name='\Controller\\'.PLATFROM_NAME.'\\'.CONTROLLER_NAME.'Controller'; //拼接控制器类名
$action_name=ACTION_NAME.'Action'; //拼接方法名
$obj=new $controller_name();
$obj->$action_name();
}

3.6 封装run()方法

1
2
3
4
5
6
7
8
9
10
class Framework{
//启动框架
public static function run(){
self::initConst();
self::initConfig();
self::initRoutes();
self::initAutoLoad();
self::initDispatch();
}
...

3.7 在入口中调用run()方法

1
2
3
<?php
require './Framework/Core/Framework.class.php';
Framework::run();

run()方法调用后就启动了框架

4 运行项目

1、连接数据库的参数从配置文件中获取

1
2
3
4
5
6
7
class Model {
...
//连接数据库
private function initMyPDO() {
      $this->mypdo= MyPDO::getInstance($GLOBALS['config']['database']);
}
}

2、更改ProductsControleller控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
namespace Controller\Admin;
//商品模块
class ProductsController {
//获取商品列表
public function listAction() {
           //实例化模型
           $model=new \Model\ProductsModel();
           $list=$model->getList();
           //加载视图
           require __VIEW__.'products_list.html';
}
//删除商品
public function delAction() {
...
$model=new \Model\ProductsModel();
...
}
}

3、更改ProductsModel类

1
2
3
4
5
<?php
namespace Model;
class ProductsModel extends \Core\Model{

}

4、更改MyPDO类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
...
private function fetchType($type){
   switch ($type){
       case 'num':
           return \PDO::FETCH_NUM;
       case 'both':
           return \PDO::FETCH_BOTH;
       case 'obj':
           return \PDO::FETCH_OBJ;
       default:
            return \PDO::FETCH_ASSOC;
  }
}
...
//所有的内置类都在公共的命名空间下。

测试:成功

5 traits代码复用

有的控制器操作完毕后要跳转,有的不需要,

解决:将跳转的方法封装到traits中。

代码实现

1、将准备好的图片拷贝到Public目录下

1561446087858.png

2、在Traits目录中创建Jump.class.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<?php
//跳转的插件
namespace Traits;
trait Jump{
   //封装成功的跳转
   public function success($url,$info='',$time=1){
       $this->redirect($url, $info, $time, 'success');
  }
   //封装失败跳转
   public function error($url,$info='',$time=3){
       $this->redirect($url, $info, $time, 'error');
  }
   /*
    * 作用:跳转的方法
    * @param $url string 跳转的地址
    * @param $info string 显示信息
    * @param $time int 停留时间
    * @param $flag string 显示模式 success|error
    */
   private function redirect($url,$info,$time,$flag){
       if($info=='')
           header ("location:{$url}");
       else{
         echo <<<str
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
   <!--
   <meta http-equiv="refresh" content="3;http://www.php.com"/>
   -->
<title>Document</title>
<style>
body{
text-align: center;
font-family: '微软雅黑';
font-size: 18px;
}
#success,#error{
font-size: 36px;
margin: 10px auto;
}
#success{
color: #090;
}
#error{
color: #F00;
}
</style>
</head>
<body>
<img src="/Public/images/{$flag}.fw.png">
<div id='{$flag}'>{$info}</div>
<div><span id='t'>{$time}</span>秒以后跳转</div>
</body>
</html>
<script>
window.onload=function(){
var t={$time};
setInterval(function(){
document.getElementById('t').innerHTML=--t;
if(t==0)
location.href='index.php';
},1000)
}
</script>
str;
       exit;
      }
  }
}

在ProductsController控制器中使用原型

1
2
3
4
5
namespace Controller\Admin;
//商品模块
class ProductsController{
   use \Traits\Jump;   //复用代码
  ...

6 删除功能

入口

1
<a href="index.php?p=Admin&c=Products&a=del&proid=<?=$rows['proID']?>" onclick="return confirm('确定要删除吗')">删除</a>

控制器(ProductsController)

1
2
3
4
5
6
7
8
public function delAction() {
$id=(int)$_GET['proid']; //如果参数明确是整数,要强制转成整形
$model=new \\Model\\ProductsModel();
if($model->del($id))
$this->success('index.php?p=Admin&c=Products&a=list', '删除成功');
else
$this->error('index.php?p=admin&c=Products&a=list', '删除失败');
}

模型、视图

1
无改变

本站由 RuntimeBroker 使用 Stellar 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本"页面"访问 次 | 👀总访问 次 | 总访客