ThinkPHP5 select出来的结果是个对象?居然还可以以数组形式访问数据?

目录

前言

  在使用TP5的过程中,我们会发现,使用select方法查询数据库中的数据后dump出来的结果是对应模型的对象。其中该对象有一个protected的data属性。而在TP3中select出来的结果返回的是一个数组。那么我们在使用TP5中select后得到了对应的结果——一个对象,怎么通过这个对象获取结果数据呢?
  结果是同样可以以数组的方式获取数据。同TP3的操作。在模板输出中,同样也使用。那为什么呢?明明这个是一个对象不是什么数组呀,怎么可以以数组的方式访问结果集呢额?
  参考:PHP中__get()和__set()的用法实例详解
     PHP实现对象属性按数组方式访问

TP5中的select方法

  【栗子】调用model创建Goods对应的模型,并使用select方法查询数据,将查询结果dump出来,如下:

public function test() {
        dump(model('Goods')->select());
    }

  运行结果如下:
TP5中的select方法返回结果
  这里可以看到它返回了一个数组,每个元素的值是一个Goods对象(它继承于Model类)。可以发现其protected的data属性保存着我们想要的结果集。我们获取结果集中的内容,同操作数组无异。如:

public function test() {
        //dump(model('Goods')->select());
        $res = model('Goods')->select();
        $goods = $res[0];
        echo 'id:' . $goods['id'] . '<br/>';
        echo 'name:' . $goods['name'] . '<br/>';
        echo 'brief:' . $goods['brief'] . '<br/>';
    }

  运行结果如下:
TP5操作select方法返回的对象

为什么可以这么操作

  既然select方法返回的对象继承于Model类,那其中的玄机一定来自这个Model类。
  (可以先阅读一下,我上面提及的参考文正。)
  首先,我们应该考虑,为什么一个对象可以以数组的形式访问。(要是一般情况下,这样去操作一个对象会报错的。)
  扣一个Model类的源码,我们会发现Model实现了ArrayAccess接口,恰恰这就是奇妙的地方所在。实现了该接口,并实现了对象的抽象方法,那么对象就可以以数组形式访问对象内保存的某些数据。
  Model类型实现ArrayAccess接口中的方法,如下:

    // ArrayAccess
    public function offsetSet($name, $value)
    {
        $this->setAttr($name, $value);
    }

    public function offsetExists($name)
    {
        return $this->__isset($name);
    }

    public function offsetUnset($name)
    {
        $this->__unset($name);
    }

    public function offsetGet($name)
    {
        return $this->getAttr($name);
    }

  我们这里先只考虑获取属性值,那么offsetGet方法就实现了 obj[key]offsetGet name,即以数组操作时传入的键的值。
  getArr的实现如下:

/**
     * 获取器 获取数据对象的值
     * @access public
     * @param string $name 名称
     * @return mixed
     * @throws InvalidArgumentException
     */
    public function getAttr($name)
    {
        try {
            $notFound = false;
            $value    = $this->getData($name);
        } catch (InvalidArgumentException $e) {
            $notFound = true;
            $value    = null;
        }

        // 检测属性获取器
        $method = 'get' . Loader::parseName($name, 1) . 'Attr';
        if (method_exists($this, $method)) {
            $value = $this->$method($value, $this->data);
        } elseif (isset($this->type[$name])) {
            // 类型转换
            $value = $this->readTransform($value, $this->type[$name]);
        } elseif ($notFound) {
            $method = Loader::parseName($name, 1);
            if (method_exists($this, $method) && !method_exists('\think\Model', $method)) {
                // 不存在该字段 获取关联数据
                $value = $this->relation()->getRelation($method);
                // 保存关联对象值
                $this->data[$name] = $value;
            } else {
                throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
            }
        }
        return $value;
    }

  在getAttr方法中中主要获取值的方法又是getData方法。
  getData方法如下:

/**
     * 获取对象原始数据 如果不存在指定字段返回false
     * @access public
     * @param string $name 字段名 留空获取全部
     * @return mixed
     * @throws InvalidArgumentException
     */
    public function getData($name = null)
    {
        if (is_null($name)) {
            return $this->data;
        } elseif (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        } else {
            throw new InvalidArgumentException('property not exists:' . $this->class . '->' . $name);
        }
    }

  TMD发现了!!!getData方法返回的便是当前对象data属性对应的值。

总结

  在这个过程中,最为关键的是Model类实现ArrayAccess接口。通过实现接口的方法,select出来的结果对象便可以通过数组的形式访问到我们想要的结果集,即对象的protected的data属性的内容。

思考

  TP5中,在使用继承于Model的模型对象时,会经常发现,我们会使用到如:$model->id的形式访问属性值,可是我们并没有在对应的模型类声明id属性呀。
  同样地,玄机还是在于这个Model类。它含有__get、__set这样两个魔术方法:

    /**
     * 修改器 设置数据对象的值
     * @access public
     * @param string    $name 名称
     * @param mixed     $value 值
     * @return void
     */
    public function __set($name, $value)
    {
        $this->setAttr($name, $value);
    }

    /**
     * 获取器 获取数据对象的值
     * @access public
     * @param string $name 名称
     * @return mixed
     */
    public function __get($name)
    {
        return $this->getAttr($name);
    }

  那么,原因我想你应该知道了。嘻嘻~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值