如何正确的检测数据模型是否存在

问题

Laravel 开发中,在检测 Eloquent 数据关系模型 是否存在时,我们经常会犯以下的错误。

以下是错误的代码演示:

// 判断是否有关联数据
if ($model->relation){
    ... 注意这是错误的演示
}

推荐方案

推荐的做法是使用 count 来判断:

// 判断是否有关联数据
if ( count($model->relation) ){
    ... 如果存在的话
}

因为 Eloquent 数据模型(Eloquent Model) 和 集合 (Collection)都实现了 ArrayAccess,所以使用 count 是通用的。

为什么不能使用 $model->relation 来判断?

接下来分「单一对应关系」和「多个对应关系」来讲解。

单一对应关系(返回数据模型 Model)

单一对应关系指的是使用以下关键词定义的关联模型:

  • hasOne
  • belongsTo
  • morphTo
  • morphOne

在单一对应关系下,使用 $model->relation 来做判断会有以下逻辑:

// 在没有对应模型的情况下
$model->relation; // 返回 null,在 if 判断里面等于 false
count($model->relation); // 返回 0,在 if 判断里面等于 false

// 存在对应模型的情况下
$model->relation; // Eloquent 数据模型(Model),在 if 判断里面等于 true
count($model->relation); // 1 ,在 if 判断里面等于 true

从上面的实例代码中可看出直接使用 $model->relationcount 函数来做判断结果一致。

多个对应关系(返回集合)

多个对应关系指的是使用以下关键词定义的关联模型:

  • hasMany
  • belongsToMany
  • morphMany
  • morphToMany
  • morphedByMany

在多个对应关系下,使用 $model->relation 来做判断会有以下逻辑:

// 没有对应模型的情况下
$model->relation; // 空集合,在 if 判断里面等于 true <--- 注意这里!!!
count($model->relation); // 0,在 if 判断里面等于 false

// 存在对应模型的情况下
$model->relation; // 非空集合,在 if 判断里面等于 true
count($model->relation); // int > 0 ,在 if 判断里面等于 true

这里的问题出在当没有对应模型时,$model->relation 会返回「空集合对象」在 if 判断里面等于 true ,使用 count 可以避免此问题。

empty() 和 集合的 ->count(), ->isEmpty() 方法

你也许在项目中使用过 empty() 和 集合的 count()、`isEmpty() 方法来判断数据模型是否存在,也许你没有错,不过,建议使用 count 来判断,原因如下:

  • empty() 对于空集合对象的话,还是会返回 true;
  • ->count() 属于集合专属的方法,无法对 Model 使用,只能在多个对应关系下使用;
  • ->isEmpty() 同上;

PHP 内置的 count 函数对以上所有情况都通杀,不论是单一、多个对应关系,不论是数组、集合,还是 Eloquent 数据模型。

Summer

摈弃世俗浮躁,追求技术精湛
本帖已被设为精华帖!
Summer
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 6
Summer

@zhuzhichao :+1: 。

还是觉得使用 count 通用,需要记的东西少点,减少犯错的可能性。

7年前 评论

PHP 7.1 某一个子版本前后,出现了更新,新版本的 count 函数会报错,提示参数必须 countable.

3年前 评论

php7.2 count 报错..

3年前 评论

wow 好细节,想起之前写的代码。。。

7年前 评论
ThinkQ

收获大

5年前 评论

由于 PHP 7.2 和 8.0 陆续提高了 count() 参数为 非 countable 类型时的报错等级,这里可以用 blank() 替代 count()

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!