控制器

文字
分享
评论收藏

3.2.4 间接读取数据

间接读取数据

直接读取数据虽然简单易懂,但往往在大型的项目中却并不适用。如果实现一个功能,我们把所有的代码都写在一个方法中,显然当功能复杂时,代码就会越来越长,越来越难以维护。这显然不是我们想看到的。
基于此,我们有了数据库M层,一个专门为我们处理数据表的文件。

M 数据模型层

没有M层以前我们取数的过程是这样的。

有了M层以后,我们取数的过程变成了这样。

是的,你想的没错,在小型的项目,或是我们这个教程中,这样做的确是画蛇添足了。但是我们的目标,并不仅仅满足于做小项目。后面你将会一点点的感受到分层的魅力。

调用谁,你就要USE谁

我们再看前面写过的代码:

如果删除或注释掉第3行。
就会报如下错误:

报错信息中提示这个类 'app\index\controller\DB' 没有找到。

原因就是我们在用Db类以前,没有告诉程序这个正确的Db类在哪个位置,怎么告诉呢?利用的就是USE。

那我们说,你怎么就知道要这么use呢?
我们先看一下,Db这个类到底在哪。

其实它在哪并不要紧,PHP中有一个叫命名空间的东西,至于怎么工作的,有兴趣的GOOGLE吧。我们只需要知道它叫命名空间就可以了。如下图所示:

命名空间,可以简单的理解为:我住哪。
我们看到Db这个类,它住在了think中,它的名字叫Db,所以别人想找它帮忙的时候,只需要use think\Db;就可以了。

当然了,我们自己写的类,由于也有命名空间,别人也可以通过我们的类住在哪,叫什么名字,来use我们的文件。
其实想搞清楚命名空间这个神奇的东西并不容易,所以搞不太清楚没有关系,我们现在只需要知道 调用谁,就USE谁 ,就可以了。慢慢的,我们会一点点的明白什么是命名空间。

调用M层,我们就要USE M层

建立M层文件

上面我们是使用了Db这个类,这次我们放弃Db类。在实际的开发过程中,大多数的数据表都是固定的(有些项目需要动态生成数据表),所以我们也很少会去用这个Db类。基于此,我们对Db类的了解,到此为止。

这次我们引用think内置的一个类think\Model,这个类中封装好了所有的数据库操作方法。我们将采用继承的方法,如果现在不太清楚什么是继承,可以直接往下看,但我们有必要去学一学C++了。

代码如下:

<?php
namespace app\model;
use think\Model;    // 使用前进行声明
/**
 * Teacher 教师表
 */
class Teacher extends Model
{

}

我们再来巩固一下这个namespace,叫做命名空间的东西。
app\model; 是指这个文件位于application文件夹下的model文件夹中。
所以当我们看到以app打头的命名空间时,也就相当于告诉了我们这个文件位于哪个位置。

是的,不仅仅我们在调用这个类之前需要进行use,我们在继承一个类之前也需要use。

调用Teacher.php 模型文件

我们先回到C层,即controller文件夹下,对原Teahcer.php进行重新编辑,去除对Db类的调用。

我们需要记往一点,只有controller文件夹下的文件,才可以通过URL访问的到。其它的文件,比如我们刚刚新建的这个M层的Teacher.php,是直接访问不到的。

删除冗余的代码后如下:

<?php
namespace app\index\controller;
/**
 * 教师管理
 */
class Teacher
{
    public function index()
    {
       echo "hello teacher";
    }
}

输入URL进行测试结果显示如下:

下面,我们正式调用Teacher模型。
1、先use;
2、再调用。

示例代码如下:

<?php
namespace app\index\controller;
use app\model\Teacher;  // 教师模型
/**
 * 教师管理
 */
class Teacher
{
    public function index()
    {
        $Teacher = new Teacher;
        dump($Teacher);
    }
}

经测试,我们将得到如下错误提示:

git checkout step3.2.4.1

执行上述命令后,上述示例代码信息如下:

提示:不能重新声明app\index\controller\Teacher这个类,原因是由于这个类已经存在。

每个班级里面只能有一个小明,如果存在两个小明,那么他们肯定有一个是大小明,另一个是小小明。因为只有这样,当老师点名的时候,才会有唯一的学生站出来。这个故事告诉我们,同一个文件中,如果有两个类的名字相同,是会发生错误的。

上述错误的原因,是由于这两个人起的名字相同的。

我们把这两个文件拿出,发现还真是这样。

解决方法1

为引用的那个Teacher 改个名字

<?php
namespace app\index\controller;
use app\model\Teacher as SmallTeacher;  // 教师模型 带有别名
/**
 * 教师管理
 */
class Teacher
{
    public function index()
    {
        $SmallTeacher = new SmallTeacher;
        dump($SmallTeacher);
    }
}
git checkout step3.2.4.2

执行上述命令后,上述示例代码信息如下:

解决方法2,更改thinkphp的命名规则,不给他们发生冲突的机会。

1、修改config.php
在config.php增加如下语句:

'controller_suffix'  => true,

修改后如下图所示:

一个新的问题产生了,为什么这个文件就没有命名空间呢?
是的,它是没有,因为我们也没有看到里面有Class的字样呀,既然它不是一个Class(类),没有就是正常的。

2、修改原来C层的文件名
Teacher.php -> TeacherController.php
当然了,如果以前的Index控制器,你还在使用的话,也是需要修改的。
修改后如图所示:

这时候,C层的类名字叫做TeacherController,M层的叫做Teacher,两个名字不一样了,当然也就不需要使用别名了。

刷新URL进行测试:
如果你见到如下错误,说明我们的config.php中的配置信息没有起作用,请检查拼写是否有错误,文件是否进行保存等。

如果你见到如下错误:

我们看到,thinkphp已经在尝试调用TeacherController了。那么,说明我们的config.php的配置信息已经配置正确,我们需要在命名空间、文件名和类名三个方面下手去找问题。

我们在以后的学习中,还会遇到上述错误,找问题的方向也是围绕命名空间、文件名、类名三个方面。

需要重点检查的项如下图所示:

由于此次我们并没有变动文件的位置,所以命名空间可以确定是没有问题的。那么问题就应该出现在文件名和类名上了。

正确的测试结果如下图所示:

我们看到,第一行提示说在debug文件的161行。显然,我们更希望看到的是在TeacherController文件的第12行,这是由于我们使用了thinkphp内置的dump()方法造成的。在以后的教程中,如果我们在其它的历史项目中看到这个函数,知道它等于var_dump()就可以了。在以后的项目或是教程中,我们将弃用dump()函数,一律改为var_dump()。

修改后代码如下:

<?php
namespace app\index\controller;
use app\model\Teacher;  // 教师模型
/**
 * 教师管理
 */
class TeacherController
{
    public function index()
    {
        $Teacher = new Teacher;
        var_dump($Teacher);
    }
}

测试结果:

git checkout step3.2.4.3

执行上述命令后,上述示例代码信息如下:

我们看到$Teacher变量的类型是一个object,这个对象的原型是app\model\Teacher。没错,的确是我们引入的那个原型。

主角登场

使用select()来获取数据库中的信息。

<?php
namespace app\index\controller;
use app\model\Teacher;  // 教师模型
/**
 * 教师管理
 */
class TeacherController
{
    public function index()
    {
        $Teacher = new Teacher;
        $teachers = $Teacher->select();
        var_dump($teachers);
    }
}

测试结果:

git checkout step3.2.4.4

执行上述命令后,上述示例代码信息如下:

我们看到返回值是个数组,这个数组的第0项是一个对象,第1项也是个对象。这两个对象都是基于app\model\Teacher这个类创建的。也就是说,这个对象中除了那些被var_dump()出来的变量以外,还有一些没有被var_dump()出来的方法可以供我们使用。

其实现在我们已经很清楚了,我们并没在app\model\Teacher中写任何代码,那么这些保护类型的私有属性是怎么来的呢?这当然是由于它继承了一个叫做think\Model类的原因了。我们说你自己是没有,但是你父类有就和你有是一样的。因为我们的继承中规定,在父类中所有的protected和public的变量或方法,都是可以被子类直接使用的。

那么好,我们现在就找一个think\Model中的方法,我们调用一下看看。

我们找到第180行的获取对象原始数据的方法。
如下:

    /**
     * 获取对象原始数据
     * @access public
     * @param string $name 字段名 留空获取全部
     * @return array
     */
    public function getData($name = '')
    {
        return array_key_exists($name, $this->data) ? $this->data[$name] : $this->data;
    }

在此,不得不说:越是技术牛气的人,代码越是规范! 
想成为技术大牛吗?从规范代码做起!

修改C层代码:

<?php
namespace app\index\controller;
use app\model\Teacher;  // 教师模型
/**
 * 教师管理
 */
class TeacherController
{
    public function index()
    {
        $Teacher = new Teacher;
        $teachers = $Teacher->select();

        // 获取第0个数据
        $teacher = $teachers[0];

        // 调用上述对象的getData()方法
        var_dump($teacher->getData());
    }
}

测试结果如下:

为getData()传参:

        // 调用上述对象的getData()方法
        var_dump($teacher->getData('name'));

再测试,结果显示如下:

增加另外两个直接显示数据的方式:

        // 调用上述对象的getData()方法
        var_dump($teacher->getData('name'));
        echo $teacher->getData('name');
        return $teacher->getData('name');

测试结果如下:

thinkphp 模型与数据表的自动关联

细心的你,发现我们并没有指定要去查哪个表,系统自动的就将Teacher表中的数据返回给了我们。

这是由于当我们新建 model\Teacher时,继承了think\Model, 在think\Model中,有个功能是自动关联数据表。也就是说,我们起的类名叫做Teacher,它就自动关联yunzhi_teacher这个表。我们说yunzhi_是在哪定义的? 再去找一下database.php吧。

是的,就这么神奇,数据表中的数据就这么过来了。

用Db类的select()方法和我们此处的select()方法,获取到的虽然都是一个数组,但是一个是数组中的子项还是数组,而另一个是数组中的子项却是对象了。由于我们并不打算使用Db类,所以在此不对这两者的区别做过多的阐述。我们只需要知道,我们是面向对象的编程思路,即:一切皆对象 就可以了。

重构代码

重新去写自己的代码就叫做重构,所以我们这里也叫重构,但我们重构的目的是越重构越清晰,而在这里重构的目标是希望大家对代码有了更加深入的理解。

重构后代码如下:

<?php
namespace app\index\controller;
use app\model\Teacher;  // 教师模型
/**
 * 教师管理
 */
class TeacherController
{
    public function index()
    {
        $JiaoShiBiao = new Teacher;
        $SuoYouJiaoShi = $JiaoShiBiao->select();

        // 获取第0个数据
        $jiaoShiZhangSan = $SuoYouJiaoShi[0];

        // 调用上述对象的getData()方法
        echo '教师姓名' . $jiaoShiZhangSan->getData('name') . '<br />';
        return '重复一遍:教师姓名' . $jiaoShiZhangSan->getData('name');
    }
}

也就是说$xxxx,xxxx是变量名,这个名字你随便起,只要前后一致就可以。这些是由我们规定好的,它们在我们的代码中第一次出现的位置是表达式的最左侧,所以我们想起什么名字,就起什么名字。
比如下图中这三项,第一次出现的位置是等号的左边,说明他们是我们建立的,我们当然有自主权了,起什么名字我们说了算。

但第一次出现的位置是等号的右边的话,那就不一样了。
这个是其他人规定好的,它怎么规定的,我们就需要怎么使用。
最简单的,比如:

        $JiaoShiBiao = new Teacher;

Teacher这个名字,是我们在use的时候规定好的,在我们的代码中出现在了等号右边,那么我们就必须按规则执行。
比如:

为了提升代码的可读性,我们必须统一代码书写的规范。
我们规定大家必须这样写:

<?php
namespace app\index\controller;
use app\model\Teacher;  // 教师模型
/**
 * 教师管理
 */
class TeacherController
{
    public function index()
    {
        // $Teacher 首写字大写,说明它是一个对象, 更确切一些说明这是基于Teacher这个模型被我们手工实例化得到的,如果存在teacher数据表,它将对应teacher数据表。
        $Teacher = new Teacher; 

        // $teachers 以s结尾,表示它是一个数组,数据中的每一项都是一个对象,这个对象基于Teahcer这个模型。
        $teachers = $Teacher->select();

        // 获取第0个数据
        $teacher = $teachers[0];

        // 调用上述对象的getData()方法
        var_dump($teacher->getData('name'));
        echo $teacher->getData('name');
        return $teacher->getData('name');
    }
}
git checkout step3.2.4.5

执行上述命令后,上述示例代码信息如下:

 
 

 

 
posted @ 2016-11-05 10:11  qiqideya  阅读(210)  评论(0编辑  收藏  举报