直接 new 对象在参数多、有校验或依赖初始化顺序时易出错:参数易混淆、默认值难维护、无法表达设置时序。Builder 应分离配置与创建,withXxx() 返回 $this 实现链式调用,build() 做最终校验并唯一构造实例。

为什么直接 new 一个对象会出问题?
当对象依赖多个可选参数、存在强校验逻辑、或内部状态需按特定顺序初始化时,new MyClass($a, $b, null, $d, true, false, ...) 这种构造方式极易出错:参数位置易混淆、默认值难维护、调用方被迫了解内部实现细节。更麻烦的是,某些属性必须在另一些属性之后设置(比如先设 $config 才能调用 initCache()),但构造函数无法表达这种时序约束。
Builder 类怎么写才不绕弯子?
核心是把“创建”和“配置”分离:Builder 不持有最终对象实例,只累积配置项;build() 方法才是真正触发对象构造的唯一入口,且只执行一次。常见错误是让 Builder 在每个 setter(如 withDatabase())里提前实例化对象——这会导致部分配置被忽略或状态不一致。
实操建议:
- Builder 类名建议为
MyClassBuilder,避免和领域类同名引发混淆 - 所有 withXxx() 方法必须返回
$this,支持链式调用 -
build()内部应做最小必要校验(如必填字段是否为空),而不是把所有业务规则塞进去 - 不要在 Builder 中暴露
getXXX()方法——它不是数据容器,只是配置中转站
示例关键片段:
立即学习“PHP免费学习笔记(深入)”;
class DatabaseClientBuilder
{
private ?string $host = null;
private ?int $port = null;
public function withHost(string $host): self
{
$this->host = $host;
return $this;
}
public function withPort(int $port): self
{
$this->port = $port;
return $this;
}
public function build(): DatabaseClient
{
if ($this->host === null) {
throw new InvalidArgumentException('host is required');
}
return new DatabaseClient($this->host, $this->port ?? 3306);
}
}
什么时候该用 Builder,什么时候该放弃?
Builder 不是银弹。如果对象只有 2–3 个参数且无依赖顺序,用构造函数 + 默认参数更直白;如果对象本身是 DTO 或纯数据结构,用数组或 stdClass 反而更轻量。
真正需要 Builder 的典型场景:
- 对象创建涉及外部资源初始化(如连接池、缓存实例、日志句柄)
- 不同环境需组合不同配置(开发环境禁用重试,生产环境开启熔断)
- 测试中需频繁构造相似但微调的对象(比如只改 timeout,其余全用默认)
- 构造过程可能抛出异常,且你希望把错误集中在
build()而非分散在各 setter 中
PHP 8.1+ 属性提升会让 Builder 变多余吗?
不会。虽然 __construct(public string $host, public int $port = 3306) 简化了简单对象的声明,但它解决不了顺序依赖和分步验证。比如你不能在构造函数里写 “先连数据库再加载 schema”,因为 $this 尚未完成初始化。Builder 的价值恰恰在于把“准备动作”从构造函数里剥离出来,交由调用方显式控制流程。
容易被忽略的一点:Builder 实例本身是可复用的。你可以构建一个基础 Builder,然后 clone 后微调生成多个变体——这在批量初始化服务客户端时很实用,但原生构造函数做不到。



















