侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

ThinkPHP:模型三大利器之三(获取器)

ThinkPHP  /  管理员 发布于 8年前   448

定义获取器

获取器的作用是对模型对象的(原始)数据做出自动处理。一个获取器对应模型的一个特殊方法(该方法必须为public类型),方法命名规范为:

getFieldNameAttr

FieldName为数据表字段的驼峰转换或者你数据表不存在的字段(注意理解后面这句话),下面是一个典型的获取器定义:

<?phpnamespace app\index\model;use think\Model;class User extends Model{    public function getUserTypeAttr($value, $data)    {        $type = [0 => '普通', 1 => 'VIP', 2 => '黄金', 3 => '白金', 4 => '钻石'];        return $type[$value];    }}

你需要给每一个需要输出转换处理的数据字段定义一个对应的获取器,但获取器的字段名不一定要和数据表的字段名一致,例如我希望给user_type字段定义一个名为getTypeAttr的获取器也是允许的,但要注意这个时候传入获取器的第一个参数肯定是没有值(因为没有对应的数据表字段数据),只能通过第二个参数获取你需要的数据。

<?phpnamespace app\index\model;use think\Model;class User extends Model{    public function getTypeAttr($value, $data)    {        $type = [0 => '普通', 1 => 'VIP', 2 => '黄金', 3 => '白金', 4 => '钻石'];        return $type[$data['user_type']];    }}

当然更为严谨的情况下,你还需要判断下是否存在$data['user_type'],这个暂且略过。

注意第二个参数的data数据,可能本身已经经过了获取器的处理(如果你定义了相关的获取器的话)。

为什么要定义一个和数据报字段不一致的获取器呢?最明显的好处可以区分不同的字段获取原始数据和处理过的数据。事实上,有很多理由可以让你定义一些数据表不存在的字段获取器,这恰恰是获取器的魅力所在。

看的出来获取器定义本身没什么难度,关键在于方法里面的获取逻辑,这是实际应用中最需要关注的。

调用获取器

定义获取器之后会在下列情况自动触发:

·模型的数据对象取值操作(例如$model->field_name);

·模型的序列化输出操作(例如$model->toArray()或toJson());

·显式调用getAttr方法(例如$model->getAttr('field_name'));

前面两种其实最终都是调用最后一种来实现的,最关键的是要理解第一种。模型对象取值的时候一般都是通过下面的方式:

$user = User::get(1);echo $user->name;echo $user->user_type;

当我们使用上面的方式进行模型对象数据获取或者在模板输出的时候事实上都会按照下面的顺序来检测和获取数据。

·第1步——如果查询结果包含该字段数据,取回原始数据,否则并进入第2步;

·第2步——检查是否定义该字段的获取器(包括动态获取器),如果有,则调用获取器返回结果,没有则进入第3步;

·第3步——检查是否定义了字段的类型转换,有则进行转换处理并返回结果,没有则进入第4步;

·第4步——如果是系统的时间字段,则自动进行时间格式化处理并返回结果,否则进入第5步;

·第5步——如果第1步检查的时候不包含该字段数据,则检查是否存在关联属性定义,有则通过关联关系获取数据并返回结果,否则抛出属性未定义的异常。

上面的这五个步骤的详细代码,如果你有兴趣的可以直接参考think\model\concern\Attribute的getAttr方法代码。

简单来说,当你获取$user->user_type的时候都会去检查是否定义了相关的获取器,而不管user_type字段是否是一个真实的数据表字段。

但很多情况下,你不会一个个去获取模型数据,而是把整个模型数据返回给客户端或者模板。

public function index(){    $user = User::get(1);    return json($user);}

在这种情况下,其实就是在响应输出的时候进行了模型的toJson处理。

有一点至关重要,如果你的获取器定义了非数据表的字段,是不会自动输出的,必须通过append方法追加额外属性(并且支持追加关联模型属性)。

如果我们定义了一个type属性的获取器(假设这并不是一个真实的数据表字段),那么需要使用下的方式才能正常输出(否则你可能只有user_type数据):

public function index(){    $user = User::get(1);    return json($user->append(['type']));}

如果你是使用toArray的话,处理方式相同。

如果是数据集查询的话,一样可以使用append方法统一追加额外字段。

public function index(){    $users = User::all();    return json($users->append(['type']));}

除了append方法之外,我们还支持用hidden方法临时隐藏一些数据。

获取原始数据

有些情况下,除了要获取处理过的数据外,还需要获取原始数据以便应对不同的需求。

如果你的获取器都是用的区分于实际数据表字段的额外属性字段,那么这个问题本身已经解决了。所以我们主要讨论的是当你的获取器属性和数据表字段一致的情况下,该如何获取原始数据。

一个最简单的办法是使用getData方法:

$user = User::get(1);// 获取user_type获取器数据echo $user->user_type;// 获取原始的user_type数据echo $user->getData('user_type');// 获取全部原始数据dump($user->getData());

动态获取器

前面我们提到过动态获取器的概念,动态获取器就是不需要在模型类里面定义获取器方法,而是在查询的时候使用闭包来定义一个字段的获取器对数据进行统一的处理。

User::withAttr('name', function($value, $data) {return strtolower($value);})->select();

如果你需要定义多个动态获取器,多次调用withAttr方法就行。

动态获取器的意义除了可以不用在模型里面定义获取器方法之外,还可以起到覆盖已经定义的获取器的作用,并且动态获取器可以支持Db类操作,弥补了Db操作不能使用获取器的缺憾,具体就看自己的需求来选择了。

Db::name('user')->withAttr('name', function($value, $data) {return strtolower($value);})->select();

总结

无论是获取器,还是之前提的修改器、搜索器,其作用无非是把你的模型工作细化和拆分,这样代码和逻辑也会更清晰,可维护性也大大增强,至于性能,从来不是模型首先考虑的。

,有大量免费的ThinkPHP入门教程,欢迎大家学习!

本文转自:https://blog.thinkphp.cn/825350

以上就是ThinkPHP:模型三大利器之三(获取器)的详细内容,更多请关注其它相关文章!


  • 上一条:
    ThinkPHP的安全注意事项
    下一条:
    ThinkPHP:模型三大利器之二(修改器)
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • thinkphp + mongodb项目中数据加载慢问题分析及解决(0个评论)
    • thinkphp6框架中封装redis操作类(0个评论)
    • thinkphp6框架中实现定时任务功能流程步骤(0个评论)
    • Thinkphp5.1框架中实现Session+Redis会话共享流程步骤(0个评论)
    • TP5框架版本5.0.10安全漏洞根据官方补丁修复,也是本站安全漏洞修复(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-12
    • 2018-01
    • 2018-02
    • 2020-03
    • 2021-07
    • 2021-12
    • 2022-05
    • 2022-06
    • 2022-09
    • 2023-01
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客