做一个自己的MVC框架[php]

2 篇文章 0 订阅
1 篇文章 0 订阅

外包的活干多了,总有一些小项目,这些小项目甚至不需要考虑安全。这时候用框架显得浪费。自己手写原生代码又有些不太习惯(框架用多了,有时候连基本的都忘了,不能忘本啊。。。)
许久不更的博客。反正也没多少人看,哈~就当给自己一个马克,也希望能给一些刚踏入程序猿大军的新手们做到一个了解MVC抛砖引玉的小作用吧。
唠唠叨叨一些废话,开始说真的。

———-我是分割线—————–
1.我对MVC的理解
再唠叨一遍MVC三个字母的含义吧
M:model->模型。一般是操作数据的地方
V:view->视图。用户肉眼直接看到的界面
C:controller->控制器。控制整个应用的作用(好难全面解释,比如之所以点保存能够保存信息而不是删掉信息,这就是控制器的作用)
所以,MVC结构在项目开发中的绝大部分作用就是从控制器(C)作为切入点[和个人习惯有关系,但是前提要架构好整体项目],调用模型接口(M)进行数据操作,并且展示在视图(V)上,以视觉的方式直观的反映给用户。

2.预设框架的基本结构
因为比较熟悉CI框架,也用过TP框架所以基本结构如下:

1).一个框架要有一个入口文件
2).框架和URL基本调用方式为
    http://基本网址/入口文件/控制器的文件夹/控制器/方法?参数名=参数值&参数名=参数值

3.文件夹结构
这里列出基本的文件及文件夹的结构

-info..........................框架文件夹
    -config....................配置文件夹
        database.php...........数据库配置文件
    -controller................用户控制器文件夹
        -test..................用户控制器文件夹
            welcome.php........用户控制器文件
    -core......................本框架的一些核心文件
        Info_Controller.php....框架的核心控制器
        Info_Model.php.........框架核心模型
        route.php..............框架的路由规则
    -models....................用户模型文件夹
        user_model.php.........用户模型文件
    -views.....................用户视图文件夹
        welcome.html...........用户视图文件
    index.php..................单入口文件

4.开始~

0).但入口文件设置基本信息

<?php
    #info/index.php:
    #声明项目根本目录
    define("SERVER_ROOT",dirname(__FILE__));
    #声明项目网址
    define("SITE_ROOT","localhost/info");
    #声明视图文件夹
    define("VIEWS_ROOT",dirname(__FILE__).'views');
    #声明控制器文件夹
    define("CONTROLLER_ROOT",'/controllers');
    #引入框架核心控制器
    require_once(SERVER_ROOT . "/core/Info_Controller.php");
    #引入框架核心模型
    require_once(SERVER_ROOT . "/core/Info_Model.php");
    #引入路由
    require_once(SERVER_ROOT . "/core/route.php");

1).路由 从URL获取所有的目标信息
URL:
localhost/info/index.php/test/welcome/hello.php?getKey=getValue
从上述URL可以提取到,
我们要调用welcome控制器下的hello方法,并且以GET方式传入了参数名:getKey,参数值:getValue这样一对k/v;
熟悉 $_SERVER 的应该知道这样一个变量 :$_SERVER[‘PATH_INFO’]。
(可以通过 var_dump($_SERVER)查看,如果没有,则说明服务器没有打开path_info,本文默认打开)
该变量可以简单地理解为记录了从脚本文件(即单入口文件)到传参开始的完整路径
即’/test/welcome/hello.php’部分,所以我们要利用该变量分割出文件夹、控制器以及方法。直接上代码比较明显

<?php 
    #info/core/index.php
    #获取controller和function
    $pathInfo = $_SERVER['PATH_INFO'];
    $pathArr = explode('/', $pathInfo);#分割文件夹、控制器和方法
    array_shift($pathArr);#删除第一个空元素,因为PATH_INFO以'/'开始
    $length = sizeof($pathArr);#获取长度用来分离出控制器和方法
    #获取路径
    $root = SERVER_ROOT . CONTROLLER_ROOT;
    for ($i=0; $i < $length-2; $i++) { 
        $root .= '/'.$pathArr[$i];
    }

    #判断类文件及类是否存在
    #命名规则为:
    #控制器文件为小写字母+'.php':welcome.php
    #控制器类名为首字母大写+'_Controller':Welcome_Controller
    $class = $pathArr[$length-2];#$pathArr的最后元素为方法名
    $className = ucfirst($class) . '_Controller';
    $classFile = $root . '/' . $class . '.php';
    unset($class);#用完释放,防止变量污染
    if (!file_exists($classFile)) {
        exit('404');
    }else{
        include $classFile;#文件存在,引入
        if (class_exists($className)) {
            $class = new $className();#类存在,实例化
        }else{
            exit('class not exist');#类不存在,报错
        }
    }

    #获取并调用function
    $functionStr = $pathArr[$length-1];
    #为了做到伪静态,有时候方法后面我们加上'.html'或者'.php'
    $functionArr = explode('.', $functionStr);
    if (sizeof($functionArr)==2) {
        $function = $functionArr[0];
        $scriptType = $functionArr[1];
    }else{
        $function = $functionArr[0];
        $scriptType = 'undefined';
    }

    #获得类和方法之后调用
    $class->$function();

因为我是在完成这个框架之后写的该文,所以一定可用。
还是给出测试吧。
在controller下新建一个文件 hello.php

    <?php 
    #测试用完即删掉该文件
    class Hello_Controller{
        public function world(){
            echo 'hello world';
        }
    }
 ?>

测试结果如图:
测试结果


2)控制器加载视图
前面已经做了URL到控制器和方法的路由,下面来做控制器加载视图。
因为PHP是一种可嵌入到HTML的脚本,所以我们可以直接在方法中include一个HTML,(好直白。。。)。同理,方法中所有在include之前声明的变量都可以直接用,但这也是一个弊端,即所有的变量都可以在HTML中使用。所以我们将include封装成一个方法,任何将要显示在HTML页面的变量都以参数的方式传给该方法。
考虑到该方法可能会被多次调用,所以封装为核心类的方法,这样每次新建一个方法只要继承核心类就可以调用。即在info_Controller.php中声明一个loadView的方法,之后controller文件夹下所有的类都extends Info_Controller即可:

<?php 
    #核心类 info/core/Info_Controller.php
    class Info_Controller{
        public function loadView($view,$data=NULL){
            #拿到参数传入的数据
            $data = $data;
            #所有视图文件都在VIEWS_ROOT中
            require_once(VIEWS_ROOT . "/$view");
        }
}
<?php 
    #用户自定义类 info/controller/test/welcome.php
    class Welcome_Controller extends Info_Controller{
        public function hello(){
            $data['key'] = 'value';
            $this->loadView('welcome.html',$data);
        }
    }
}
<!-- 视图文件 /info/views/welcome.html -->
<html>
    <head>

    </head>
    <body>
        <?php var_dump($data);?>
        <h1>helloworld</h1>
    </body>
</html>

测试结果:
控制器加载视图


3)控制器调用模型
模型层我们主要是用来进行数据库操作。首先我们要连接数据库。
连接数据库的信息,一般我们都放在单独的配置文件,连接的时候直接引入该文件即可。

<?php 
    #/info/config/database.php
    $_DATABASE['DBdriver'] = 'mysql';
    $_DATABASE['host'] = 'localhost';
    $_DATABASE['port'] = '3306';
    $_DATABASE['username'] = 'root';
    $_DATABASE['password'] = 'root';
    $_DATABASE['database'] = 'bbs';

同2),我们肯能要多次进行数据库操作,所以每次都去connect数据库太繁琐,这里我们把连接数据库的操作写在核心model文件:info_model.php的构造函数中,这样之后我们每次新建一个模型的时候直接继承核心model类即可。

<?php 
    #info/core/Info_Model.php
    #这里我们使用PDO进行连接
    require_once(SERVER_ROOT . "/config/database.php");
    class Info_Model{
        function __construct(){
            #链接数据库
            global $_DATABASE;#方法外的变量通过global引入
            $driver = $_DATABASE['DBdriver'];
            $host = $_DATABASE['host'];
            $port = $_DATABASE['port'];
            $username = $_DATABASE['username'];
            $password = $_DATABASE['password'];
            $database = $_DATABASE['database'];
            $this->db = new PDO("$driver:host=$host;dbname=$database;charset=utf8mb4",$username,$password);
            $this->db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE,PDO::FETCH_ASSOC);#默认返回关联数组
            $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); #禁用prepared statements的仿真效果
        }
    }

每个model文件中的类需要实例化之后才能使用。所以我们可以像2)中加载视图一样,在核心控制器中封装一个加载模型的函数

<?php 
    #/info/core/Info_Controller.php
    class Info_Controller{
        #加载控制器
        public function loadView($view,$data=NULL){
            $data = $data;
            require_once(SERVER_ROOT . "/views/$view");
        }

        #加载模型
        public function loadModel($model,$alias=NULL){
            $modelFile = SERVER_ROOT . "/models/$model" . '.php';
            if (!file_exists($modelFile)) {
                exit('404');
            }else{
                require_once($modelFile);
                #参考CI,可以给调用的模型一个别名
                if ($alias) {
                    $this->$model=$this->$alias = new $model();
                }else{
                    $this->$model = new $model();
                }
            }
        }
    }

新建一个模型。

<?php 
    #/info/model/user_model.php
    class user_model extends Info_Model{
        #声明一个读取数据库中所有用户数据的方法
        #在此之前要在数据库中新建一个用户表‘user_info’并加入一些数据
        public function getAllUserInfo(){
            $sql = 'select * from user_info';
            $data = $this->db->query($sql)->fetchAll();
            return $data;
        }
    }

在自定义的控制器中加载该模型并调用上面声明的方法

<?php 
    class Welcome_Controller extends Info_Controller{
        public function hello(){
            #加载模型并且给一个别名。
            $this->loadModel('user_model','user');
            #调用该模型的方法(获取用户数据)
            $userinfo = $this->user->getAllUserInfo();
            var_dump($userinfo);
        }
    }

测试结果:
控制器加载模型


到这里基本上就结束了。
这只是一个简单的MVC。没有考虑的太多。欢迎指正。
附上代码链接:
http://download.csdn.net/detail/u013332865/9705768

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值