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

来源:互联网 发布:淘宝商城妈妈装 编辑:程序博客网 时间:2024/05/21 11:14

外包的活干多了,总有一些小项目,这些小项目甚至不需要考虑安全。这时候用框架显得浪费。自己手写原生代码又有些不太习惯(框架用多了,有时候连基本的都忘了,不能忘本啊。。。)
许久不更的博客。反正也没多少人看,哈~就当给自己一个马克,也希望能给一些刚踏入程序猿大军的新手们做到一个了解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
原创粉丝点击