
PHP 8.5 里工厂模式不是语言特性,是自己写的类
PHP 8.5 没有内置 Factory 关键字或语法糖,所谓“工厂模式”就是你写一个普通类(比如 DatabaseFactory),用它的方法返回不同实例。别被版本号误导——它只是让你能更安全地用 new、更方便地配合构造器属性提升(public function __construct(public string $host)),但工厂本身还是得手写。
怎么写一个不踩坑的简单工厂(以数据库连接为例)
常见错误是把工厂写成静态方法大杂烩,一加新类型就得改工厂代码,违反开闭原则;或者硬编码类名字符串,IDE 不提示、重构易出错。
- 用接口统一返回类型:
interface DatabaseConnection,所有具体类(MysqlConnection、PostgresConnection)都实现它 - 工厂方法参数用枚举或受控字符串(比如
enum DbType: string { case MYSQL = 'mysql'; case POSTGRES = 'postgres'; }),避免传'MySQL'和'mysql '这种拼写/空格错误 - 构造时直接传依赖,别在工厂里 new 配置对象——配置应由上层注入,工厂只负责“选哪个类、用哪些参数 new 出来”
class DatabaseFactory
{
public function __construct(private array $configs) {}
public function create(DbType $type): DatabaseConnection
{
return match ($type) {
DbType::MYSQL => new MysqlConnection($this->configs['mysql']),
DbType::POSTGRES => new PostgresConnection($this->configs['postgres']),
};
}
}
PHP 8.5 特性怎么帮上忙
相比老版本,8.5 的几个点能让工厂更稳、更易读,但不是必须用:
-
match表达式替代switch:自动返回值、严格类型、穷尽检查(如果枚举加了新 case 而没更新match,会报UnhandledMatchError) - 构造器属性提升 + 命名参数:实例化具体类时可写
new MysqlConnection(host: '127.0.0.1', port: 3306),工厂里调用更清晰 - 联合类型 +
never:工厂方法返回类型可声明为DatabaseConnection|never,配合match穷尽后,PHP 能确认不会返回 null 或意外类型
容易被当成“工厂”的伪模式
这些看着像工厂,实际不是,容易混淆职责:
立即学习“PHP免费学习笔记(深入)”;
-
__invoke()当工厂:比如$factory = new DatabaseFactory(...); $conn = $factory('mysql');—— 可行但模糊,不如明确方法名create() - 依赖注入容器(如
PHP-DI)当工厂:容器能做工厂的事,但它解决的是生命周期+依赖解析,不是单一对象创建逻辑;混用会导致工厂逻辑散落在配置和代码里 - 抽象工厂里塞太多判断:比如一个工厂同时管数据库、缓存、日志——该拆成
DatabaseFactory、CacheFactory,否则单个类膨胀、测试难写
真正要小心的是:工厂类自己开始读配置文件、连数据库、处理异常重试——那就越界了。它只该决定“new 哪个类”,别的交给具体类或上层协调。











