自己动手写PHP框架(三)

作者:Terry Gao

1. 控制器

第一篇我们聊到路由分发会把用户请求按照规则分发到控制器层的不同类,而默认的规则中,请求会下发到控制器的index类的main方法,我们可以在这个方法中处理用户请求,并将处理结果呈现给用户。来看看源码

/* Nova/Application/Controllers/index.php */
<?php
namespace Nova\Application\Controllers;

class index
{
    public function main()
    {
        echo "Hello World!";
    }
}

很基础,很简单,就是输出一个”Hello World!”。你会说“用户的请求呢?用户的请求体现在哪里?我没看出来啊!”

好吧,我们来稍微复杂一点。假设我们站点的域名是nova.local,用户请求地址:http://nova.local/?act=user&st=info&id=1。根据Nova的路由规则,act=user意味着它请求的是Nova\Application\Controllers\user.php的user类,st=info对应着user::info()方法,用来获取用户信息,而id=1则是user::info需要通过GET接收的一个参数,我们可以在user::info中对id进行解析和处理,获取id为1的用户信息,然后输出给用户。源代码如下:

/* Nova/Application/Controllers/user.php */
<?php
namespace Nova\Application\Controllers;
use Nova\Application\Models;

class user
{
    public function info()
    {
        $mUser = new Models\user();
        $userInfo = $mUser->getUserInfo($_GET['id']);
        print_r($userInfo);
    }
}

上面的代码,没什么安全性可言,GET的信息没有任何过滤和校验,由于这个系列文章只是介绍基本的框架思路,所以这部分内容不是我们的重点,请暂且忽略(如果你实在看不下去如此ugly的代码,可以在Github上Fork Nova项目,然后提Pull Request给我)。

在info()方法中,我们新建了一个Models\user类,然后调用Models\user::getUserInfo()方法,来处理$_GET[‘id’],并将获取到的用户信息通过print_r()方法打印出来。这里的Models\user类就是MVC中M层的一个实现。

2. 模型层

我们可以将数据组织和处理逻辑放在模型层,这里封装了数据库操作,甚至有些大型的框架会在这一层对这个数据库进行对象化,目的都是为了组织和处理数据,然后将处理好的数据返回给控制器层。上一节提到的Models\user类就是一个专门用于处理用户数据的模型类,来看看源码:

/* Nova/Application/Models/user.php */
<?php
namespace Nova\Application\Models;
use Nova\Framework\PDOMysql;

class user
{
    protected $db;

    public function __construct()
    {
        //使用PDO创建mysql数据库连接
        $this->db = PDOMysql::connect()->db;
    }

    /**
     * 根据用户id查询用户信息并返回查询结果
     *
     * @return array
     */
    public function getUserInfo($userId)
    {
        $sql = 'select * from user where id=:userId';

        $stmt = $this->db->prepare($sql);
        $params = array(':userId' => $userId);
        $stmt->execute($params);

        return $stmt->fetch();
    }
}

这个类在构造的时候创建了一个数据库连接,然后在getUserInfo()方法中根据传入的用户id查询对应的用户信息,并将查询结果返回给调用者(控制器)。

通过下图来看看到目前为止,我们有什么了

Nova

好吧,看出来了,MVC的View没有。View层有一个好东西,也许你听过,甚至你用过,对,就是Smarty,这么好的东西拿来直接用吧。把Smarty的源码下载下来,然后统统解压到Nova/Application/Library/Smarty下面,我们要怎么把Smarty加载进来呢?首先改造一下Controller层,新建一个Controllers\base.php,作为控制器层的基类,在这里我们引入并初始化一下Smarty,代码如下:

/* Nova/Application/Controllers/base.php */
<?php
namespace Nova\Application\Controllers;
//引入Smarty的Autoloader
require_once APP_DIR . '/Library/Smarty/Autoloader.php';

class base
{
    public $smarty;

    public function __construct()
    {
        //调用Smarty的Autoloader
        \Smarty_Autoloader::register();
        //创建Smarty的一个实例化对象
        $this->smarty = new \Smarty();
        //对smarty做一些基本设置
        //设置模板的存放位置
        $this->smarty->setTemplateDir(APP_DIR.'/Views/');
        //smarty编译文件的存储位置
        $this->smarty->setCompileDir(ROOT_DIR.'/compiled/');
        //设置smarty配置文件的存放位置
        $this->smarty->setConfigDir(CONFIG_DIR.'/smarty/');
        //smarty自带缓存,设置缓存的存储位置
        $this->smarty->setCacheDir(ROOT_DIR.'/cache/');
    }
}

然后我们让Controllers\user继承Controllers\base,就可以使用smarty了

/* Nova/Application/Controllers/user.php */
<?php
namespace Nova\Application\Controllers;
use Nova\Application\Models;

class user extends base
{
    public function info()
    {
        $mUser = new Models\user();
        $userInfo = $mUser->getUserInfo($_GET['id']);

        //将数据传入给smarty
        $this->smarty->assign('user', $userInfo);
        //通过smarty的display函数,调用index.tpl模板来显示数据
        $this->smarty->display('index.tpl');
    }
}

模板代码如下:

/* Nova/Application/View/index.tpl */
<div>User Name: {$user['name']}</div>
<div>Password: {$user['password']}</div>

至此,MVC齐全了,整个架子搭起来喽。运行一下试试看吧。
你可以在Github上查看Nova项目的源代码。

如果你有任何问题或建议,可以扫描下方二维码或者为微信搜索[phpjiagoushier],关注我的微信公众号[PHP架构师],与我交流互动。
phpjiagoushier

发表评论

邮箱地址不会被公开。 必填项已用*标注