MySQL的CHECK约束需通过SQL语句在数据库层面添加,PHP仅能借助PDO或mysqli执行ALTER TABLE语句实现,且要求MySQL≥8.0.16、InnoDB引擎。
PHP 本身没有“添加 CHECK 约束”的语法;CHECK 是数据库层面的约束,必须通过 SQL 语句交给 MySQL(或 PostgreSQL)执行。你在 PHP 里能做的,是用 PDO 或 mysqli 发送 ALTER TABLE ... ADD CONSTRAINT 这类语句。如果只在 PHP 代码里写个 if 判断,那叫应用层校验,不是数据库约束。
必须确保 MySQL 版本 ≥ 8.0.16(早期版本忽略 CHECK),且存储引擎是 InnoDB。以下用 PDO 示例:
$pdo = new PDO('mysql:host=localhost;dbname=test', $user, $pass);
$pdo->exec("ALTER TABLE users ADD CONSTRAINT chk_age CHECK (age >= 0 AND age <= 150)");
chk_age 是约束名,建议起有意义的名字,便于后续排查NOW())、子查询或其它表字段ALTER TABLE 会直接报错:Check constraint 'chk_age' is violated
SELECT COUNT(*) FROM users WHERE age 150 预检数据数据库 CHECK 只防写入,不防应用逻辑错误、不拦 API 请求、也不提供友好提示。所以实际项目中,你通常得同时做两件事:
CHECK (status IN ('active', 'inactive', 'pending')) 防脏数据入库in_array($input['status'], ['active', 'inactive', 'pending']) 提前拦截并返回 JSON 错误filter_var() 或 filter_input() 适合基础类型校验(如邮箱、整数),但无法替代业务规则(如“结束时间必须晚于开始时间”)Rule::unique('users')->where(fn ($q) => $q->where('deleted_at', null)),这类是 ORM 层校验,
很多人试了没效果,其实不是 PHP 写错了,而是踩了这些坑:
MyISAM 引擎 —— 它完全忽略 CHECK 约束,连警告都不报sql_mode 不含 STRICT_TRANS_TABLES),导致违反 CHECK 的 INSERT 被静默转成默认值CHECK 关键字mysql_connect 已废弃),或未设置 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,导致错误被吞掉真正可靠的 CHECK 约束,得靠数据库自己 enforce,PHP 只负责把语句发过去,并检查是否执行成功。别指望它在 PHP 里“运行”这个约束。