php 8联合类型削弱了strategy/factory/null object等模式的必要性,通过函数签名类型声明替代运行时判断,简化逻辑并提升静态分析能力,但未解决领域语义混淆问题。

PHP 8 的联合类型(Union Types)本身不颠覆设计模式,但它显著削弱了某些传统模式存在的必要性——尤其是那些为绕过弱类型限制而生的、纯类型适配类的模式。
Union Types 直接替代了 Strategy/Factory 中大量类型判断逻辑
过去写一个处理多种输入格式的服务类,常靠 if-elseif 或 switch 判断类型再分发,比如:
旧写法(伪代码):
function handle($input) {
if (is_string($input)) {
return $this->handleString($input);
} elseif (is_int($input)) {
return $this->handleInt($input);
} elseif ($input instanceof SomeDTO) {
return $this->handleDTO($input);
}
throw new InvalidArgumentException('Unsupported type');
}
现在用 Union Types + match,类型声明即契约,分支逻辑更紧凑、不可绕过:
function handle(string|int|SomeDTO $input): string {
return match(true) {
is_string($input) => 'string: ' . strtoupper($input),
is_int($input) => 'int: ' . ($input * 2),
$input instanceof SomeDTO => 'dto: ' . $input->id,
};
}
-
Union Types把运行时类型检查前移到函数签名,IDE 和静态分析能立刻捕获非法调用 - 不再需要额外的
isValidInput()验证方法或InputValidator类 - 如果业务逻辑确实需要多态行为,
match已足够清晰;强行套Strategy反而增加抽象层级
Factory 模式在构造器属性提升 + Union Types 下变得更轻量
以前为了统一创建不同类型的处理器,常写一个 HandlerFactory:
class HandlerFactory {
public static function make(string $type): HandlerInterface {
return match($type) {
'json' => new JsonHandler(),
'xml' => new XmlHandler(),
default => throw new RuntimeException('Unknown handler'),
};
}
}
PHP 8 后,若类型信息已通过参数传入(比如 array|string $config),直接用联合类型 + 构造器提升即可内聚处理:
class ConfigurableHandler {
public function __construct(
public array|string $config,
public string $format
) {}
<pre class="brush:php;toolbar:false;">public function parse(): array {
return match($this->format) {
'json' => json_decode($this->config, true) ?: [],
'xml' => $this->parseXml($this->config),
default => throw new InvalidArgumentException('Unsupported format'),
};
}}
- 不需要单独的工厂类,构造即明确依赖
-
array|string $config声明比mixed+ 注释更可靠,也比抽象工厂返回HandlerInterface更直白 - 若后续要扩展新格式,改
match分支比新增子类+注册到工厂更少跳转
Null Object 模式使用频率下降,但没消失
Union Types 允许你显式写出 Service|null,配合 nullsafe 运算符(?->),很多场景下无需再定义一个空实现类:
// 以前
interface CacheInterface { public function get(string $key); }
class NullCache implements CacheInterface { public function get(string $key) { return null; } }
<p>// 现在
function process(CacheInterface|null $cache): void {
$data = $cache?->get('user_123') ?? 'default';
}</p>
-
CacheInterface|null比CacheInterface+NullCache更少样板,调用方也更清楚“可能为空”是契约一部分 - 但如果空行为复杂(比如要记录日志、触发告警),仍需真实对象,
Null Object仍有价值 - 注意:
?->不会阻止TypeError,它只跳过null调用;若$cache是false或0,?->不生效
真正容易被忽略的是:联合类型不解决领域语义混淆问题。比如 string|int 能过类型检查,但 "123" 和 123 在业务上是否等价?这仍需领域建模判断,不能只靠类型系统兜底。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











