1 框架目录
1.1 创建目录结构

1.2 文件分类存放

将文件存放到不同的目录以后,由于类文件地址发生了变化,所以无法完成自动加载类,那么今天的主要任务就是围绕如何实现类的自动加载展开。
由于每次都请求入口文件,所以”.“表示入口文件所在的目录
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;
class ProductsModel extends Model{ ...
|
ProductsController.class.php
1 2 3 4 5
| <?php namespace Controller\Admin;
class ProductsController { ...
|
3 框架类实现
3.1 定义路径常量
由于文件路径使用频率很高,而且路径比较长,所以将固定不变的路径定义成路径常量
知识点
1 2
| 1、getcwd():入口文件的绝对路径 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); 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】方法

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'))) $path= FRAMEWORK_PATH.$namespace.DS.$class_name.'.class.php'; elseif($namespace=='Model') $path=MODEL_PATH.$class_name.'.class.php'; elseif($namespace=='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目录下

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'); }
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', '删除失败'); }
|
模型、视图