type
Post
status
Published
date
May 24, 2015
slug
create-a-php-framework
summary
个人觉得徒手写一个PHP框架是帮助我们了解MVC架构的好办法,同时对PHP的资源调度以及代码组织都是一个很好的锻炼。
tags
PHP
category
技术分享
icon
password
Property
Dec 25, 2022 09:20 AM
开始
首先我们建立基本的文件夹结构,如下:
application ——controller ——model ——view system index.php
application
是项目的目录,而system不用说就是框架文件的目录了。
index.php
是我们所有请求的入口,我们规定通过如下的url来调用controller
:localhost/index.php?c=controller&a=action¶m=123
设置index.php 入口以及路由
因为所有的请求都是通过
index.php
发起的,因此我们需要在index.php
里面进行一些初始化的设置:define('BASE_ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR); define('APP_ROOT', BASE_ROOT . 'application' . DIRECTORY_SEPARATOR);
因为我们规定url参数中的
c
是控制器名,a
是方法名,因此index.php
中需要一个路由函数去活取这两个参数:define('BASE_ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR); define('APP_ROOT', BASE_ROOT . 'application' . DIRECTORY_SEPARATOR); function route(){ $c = isset($_GET['c'])?$_GET['c']:'index'; $a = isset($_GET['a'])?$_GET['a']:'index'; $r['c']=ucfirst(strtolower(trim($c))); $r['a']=strtolower(trim($a)); return $r; } $routeArr = route(); $controller=$routeArr['c']; $action=$routeArr['a'];
获取到了需要实例化的controller以后,就可以进行相关操作了:
define('BASE_ROOT', dirname(__FILE__) . DIRECTORY_SEPARATOR); define('APP_ROOT', BASE_ROOT . 'application' . DIRECTORY_SEPARATOR); function route(){ $c = isset($_GET['c'])?$_GET['c']:'index'; $a = isset($_GET['a'])?$_GET['a']:'index'; $r['c']=ucfirst(strtolower(trim($c))); $r['a']=strtolower(trim($a)); return $r; } $routeArr = route(); $controller=$routeArr['c']; $action=$routeArr['a']; //根据route的参数加载所需的文件 if (file_exists(APP_ROOT . 'controller/' . $controller.'Controller.php' )){ require_once APP_ROOT . 'controller/' . $controller.'Controller.php'; $obj=new $controller(); if (method_exists($obj,$action)){ $obj->$action(); }else{ die('func not exist'); } }else{ die('file not exist'); }
创建测试控制器
我们在
controller
文件夹里面创建一个 IndexController.php
文件:class IndexController{ public function test(){ echo 'test data'; } }
试一试
localhost/index.php?c=index&a=test
,不出意外就能得到test data
了。提取父类控制器
光是这样肯定是不够的,因为我们需要在controller里面连接model,调用模板,加载各种工具类等。因此我们需要一个带一些公用方法的
父类,这个父类可以被所有的controller继承。
我们创建一个
controller.php
文件:class controller { //打印的方法 public function dump($data){ echo '<p>'; print_r($data); echo '</p>'; die; } }
这样一个简单的父类就完成了,里面带了一个很常用的格式化打印数据的方法。那么这个父类我们放在哪里呢? 最简单的方法就是放在
application/controller
文件夹里面了,但是一般来说application文件夹是用来放我们项目本身的代码的,框架的代码我们最好放在
system
文件夹里面,然后通过__autoload()
函数自动调用。我们可以在index.php 里面添加这个函数:
function __autoload($className){ if(file_exists(BASE_ROOT . 'system/' . $className . '.php')){ require_once BASE_ROOT . 'system/' . $className . '.php'; } }
接下来我们就能在项目的controller继承这个父类了:
class IndexController extends Controller { public function test(){ $this->dump('test data'); } }
Model
接下来我们在application文件夹下面创建model文件夹,用来存放模型。那怎么通过controller来调用model?自然就是通过父类自带
的方法了。我们在
controller.php
里面添加一个方法:public function model($modelName){ $modelFile = $modelName . 'Model'; return new $modelFile(); }
单是这样还不行,因为php并不知道我们试图实例化的这个model文件在哪里,因此我们需要通过
__autoload()
函数告诉PHP:function __autoload($className){ if(file_exists(BASE_ROOT . 'system/' . $className . '.php')){ require_once BASE_ROOT . 'system/' . $className . '.php'; }elseif(file_exists(APP_ROOT . 'model/' . $className . '.php')){ require_once APP_ROOT . 'model/' . $className . '.php'; } }
然后我们就可以写一个测试用的
TestModel.php
了:class TestModel { public function findData(){ return 'model data'; } }
试着在
TestController.php
里面调用看看:class IndexController extends Controller { public function test(){ $testModel = $this->model('Test'); echo $testModel->findData(); //输出 model data; } }
连接数据库
但是现在的model是无法连接数据库的,这样的model就是个废物。但是在每一个model里面写连接数据库的方法是很蠢的,最好的
方法就是通过父类的model连接数据库,其他model继承父类就好了。
和controller.php相同,我们在
sysytem
文件夹下创建一个model.php
:class model { protected $_db; public function __construct(){ $this->_db=new mysqli('localhost', 'root','123456', 'myphp'); if(mysqli_connect_errno()){ echo 'error...'.mysqli_connect_errno(); } } public function query($sql){ $result=$this->_db->query($sql); if($result->num_rows){ while ($row = $result->fetch_assoc()) { $myRow[] = $row; } return $myRow; } } }
自然我们所有的model都继承这个父类model:
class TestModel extends Model { // other code...... }
让我们在本地建立一个
myphp
数据库,再新建一个user
表,格式如下:id | name | age |
1 | zhang | 20 |
2 | shao | 21 |
3 | wang | 22 |
让我们写一个
UserController
连接UserModel
查找数据,所以我们要这么做:在
application/controller
文件夹下面创建UserController.php
,内容如下:class UserController extends Controller { public function user(){ $id = $_GET['id']; $userModel = $this->model('User'); $user = $userModel->getUser($id); $this->dump($user); } }
在
application/model
文件夹下面创建UserModel.php
,内容如下:class UserModel extends Model { public function getUser($id){ $sql = 'select * from user where id ='.$id; $data = $this->query($sql); return $data; } }
试着通过
localhost/index.php?c=user&a=user&id=1
请求看看吧!