业务规则必须写在方法里,不能塞进属性声明中,因为php属性仅存储数据,不支持执行逻辑,类型声明和readonly只约束类型与可变性,不提供校验入口;应置于__construct()、setter或独立验证方法中。

业务规则必须写在方法里,不能塞进属性声明中。
为什么属性里不能放业务规则
PHP 的属性($var)只是存储数据的容器,不支持执行逻辑。即使你用 PHP 7.4+ 的类型声明(如 public string $email;)或 PHP 8.2+ 的 readonly,它们只约束类型、可变性或是否允许动态属性,**不提供校验入口、不触发回调、不支持条件判断**。
常见错误现象:
- 试图在属性声明时做格式检查:
public string $email = filter_var($input, FILTER_VALIDATE_EMAIL) ?: throw new InvalidArgumentException();→ 语法错误,PHP 不允许在属性默认值中写表达式或语句 - 把验证逻辑藏在 getter 里但忽略构造阶段:
public function getEmail() { return filter_var($this->email, FILTER_VALIDATE_EMAIL) ? $this->email : null; }→ 外部早已通过$user->email = 'xxx';写入非法值,getter 只是“事后补救”,状态已脏
业务规则该放在哪些方法里
根据规则触发时机和职责分离原则,优先按以下顺序考虑:
-
__construct():强制初始化校验。例如邮箱格式、必填字段非空、ID 为正整数等“对象诞生即合法”的规则 -
__set()或 setter 方法(如setEmail()):控制后续修改。适合需要拦截赋值、转换格式(如 trim、strtolower)、或联动更新其他属性的场景 - 独立的验证方法(如
isValid()或validate()):当规则复杂、依赖外部服务(如查重)、或需批量校验多个字段时使用,不耦合在赋值流程中
示例(构造 + setter 双保险):
class User
{
private string $email;
public function __construct(string $email)
{
$this->setEmail($email); // 复用校验逻辑
}
public function setEmail(string $email): void
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email format');
}
$this->email = $email;
}
public function getEmail(): string
{
return $this->email;
}
}
容易踩的坑:把规则“分散”或“延迟”处理
以下做法看似灵活,实则破坏封装性和一致性:
- 只在 DAO 层或控制器里做校验 → 类本身失去内聚,
User对象可以合法地持有一个非法$email,违背“对象即契约”的设计直觉 - 用
public属性 + 文档约定“请勿直接赋值” → PHP 不强制,IDE 不提示,运行时零防护 - 把规则写在
__get()里返回修正后的值(如自动 trim)→ 调用方拿到的不是真实存储值,调试困难,且无法区分“原始输入”和“标准化输出”
真正关键的点在于:业务规则是对象行为的一部分,不是数据的修饰;它必须能被明确调用、可测试、可追溯。一旦规则游离出类的方法边界,就等于把校验责任推给使用者,而封装的核心价值正在于收回这份责任。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











