find()返回单条记录(对象或null),select()固定返回Collection集合;查单条用find(),查多条用select(),勿混淆遍历与计数操作。

find() 返回单条记录(对象或 null),select() 固定返回集合(Collection 对象),别拿 find() 当数组遍历,也别对它用 count() ——这是最常踩的坑。
查单条还是查多条,看方法名就该知道行为
find() 和 select() 的语义是明确的:前者只取一条,后者取全部匹配项。很多人写 User::find(123) 后直接 foreach,一运行就报错。
-
find()适合主键精确查询、或确定结果唯一(如登录态查用户);传空条件会取主键最小那条,不是随机 -
select()返回的是think\model\Collection实例,不是原生数组;要转成数组得显式调toArray() - 想查单条但又带复杂条件,优先用
where(...)->find(),别用where(...)->select()->first()—— 多一次对象构造,还绕 - 模型里还有
get()和all(),它们是模型专属方法,和find()/select()行为一致,但不支持链式调用 Query 方法(比如不能get()->order())
where 条件写错,数据库可能“假装查到了”
ThinkPHP 的 where() 在类型不匹配时往往静默失败,尤其开启 PDO 真实预处理后,where('status', '1') 可能根本不出 SQL。
- 数字字段别传字符串:
where('status', 1),不是'1' - 模糊查询必须手动加
%:where('name', 'like', '%admin%'),写成'admin'就是等值匹配 -
IN必须传数组:where('id', 'in', [1,2,3]);传字符串'1,2,3'会生成IN ('1,2,3'),不是三个值 - 查
NULL别用等号:where('email', null)生成= NULL(永远 false),改用whereNull('email')或where('email', 'null')
多表关联别手写 foreach 嵌套
像这种先查订单再循环查用户信息的写法:
$orderData = $table1->where($map)->select();
$data = [];
foreach ($orderData as $v) {
$myClient = $table2->where(['id' => $v['tid']])->find();
if ($myClient) $data[] = $myClient;
}
在数据量稍大时就会变慢、内存涨、SQL 执行次数爆炸。
立即学习“PHP免费学习笔记(深入)”;
- 用
join()一次查出:UserModel::alias('u')->join('order o', 'u.id = o.user_id')->select() - 关联定义好后,直接
with('orders')懒加载或预加载,比手写 join 更安全、可读性更好 - 如果只是取关联字段(比如订单里的用户名),用
field()显式指定,避免查出整张用户表字段 - 注意
join默认是LEFT JOIN;要INNER JOIN得写全:join('INNER JOIN order o ON u.id = o.user_id')
容易被忽略的返回值类型和判空方式
find() 可能返回对象、null,甚至某些旧版本里是 false;select() 总是返回 Collection,空结果也是非空对象。
- 判
find()是否有值,用is_null($user)或更稳妥的$user ?? [],别用empty($user)—— 对象永远不为空 - 取字段值统一用
getData(),比如$user->getData('name');直接$user->name在有访问器/修改器时可能触发额外逻辑 - 关联字段(如
$user->posts)可能为null或空集合,用前务必判空:if ($user->posts && $user->posts->count()) -
Collection支持each()、filter()等方法,比foreach+if更函数式,也更少出错



















