直接查数据库比调用PHP函数更可靠,因PHP无内置栏目收藏数量计算函数,须依赖user_favorite表通过COUNT(*)统计,并确保索引、预处理、登录校验及原子操作以保障性能与一致性。

直接查数据库比调用PHP函数更可靠
PHP本身没有内置的“栏目收藏数量”计算函数,所谓“栏目收藏”是业务逻辑概念,必须依赖你自己的数据表结构。常见做法是建一张 user_favorite 表,字段至少包含 user_id、category_id、created_at;计数就是对指定 category_id 的行做 COUNT(*)。
- 别试图用
array_count_values()或count()在 PHP 层聚合——数据量一上来就内存溢出或超时 - 如果用了 Redis 缓存收藏数,务必在用户增删收藏时同步更新
INCRBY/DECRBY,否则缓存和 DB 不一致 - 注意 MySQL 的
WHERE category_id = ?必须有索引,否则慢查询会拖垮整个列表页
用 PDO 预处理语句安全计数
避免拼接 SQL 导致注入,尤其 category_id 来自 GET 或路由参数时。以下是最小可用示例:
$stmt = $pdo->prepare("SELECT COUNT(*) FROM user_favorite WHERE category_id = ?");
$stmt->execute([$categoryId]);
$favoriteCount = (int) $stmt->fetchColumn();
注意:fetchColumn() 返回的是字符串,强制转 (int) 可防空值或非数字干扰;若 $categoryId 可能为字符串(如 UUID 栏目 ID),则需确认字段类型匹配,否则索引失效。
前端展示前先判断是否登录
未登录用户不该看到“已收藏”或真实计数,否则暴露数据规模或引发权限误判。典型错误是直接输出 $favoriteCount 而不校验身份:
立即学习“PHP免费学习笔记(深入)”;
- 登录态检查应放在计数查询之前,比如
if (!isset($_SESSION['user_id'])) { $favoriteCount = 0; } - 某些场景(如公开排行榜)允许匿名查看总数,但需明确区分“该栏目被收藏次数”和“当前用户是否收藏”,后者必须鉴权
- 别把计数结果直接塞进 HTML 注释里(如
),可能被爬虫批量采集
高并发下计数不准怎么办
当多个用户几乎同时收藏/取消同一栏目,单纯 SELECT + UPDATE 容易覆盖彼此,导致最终计数偏差。根本解法不是加锁,而是改用原子操作:
- MySQL:用
INSERT ... ON DUPLICATE KEY UPDATE确保唯一性,再查总数 - Redis:用
ZADD存用户 ID 到栏目维度的有序集合,ZCARD获取实时总数(适合读多写少) - 避免在 PHP 中做“先查再判再改”三步操作,这中间任何一步失败都会让状态脱钩
真正麻烦的不是怎么写代码,而是你得想清楚:这个“收藏数量”到底要不要强一致性?大多数后台管理场景只要最终一致就行,但首页曝光位可能需要秒级准确——这决定了你该用 DB 还是缓存,以及要不要引入消息队列削峰。











