PHP可复用组件的核心在于接口契约、依赖隔离与明确边界:必须用Composer按PSR-4自动加载,类名路径严格对应;依赖须抽象为接口并由使用者注入,禁用硬编码和new具体类;强制PHP 8+严格类型声明;测试需覆盖null、空值、异常流等边界场景。

PHP可复用组件不是靠“写得漂亮”实现的,而是靠接口契约、依赖隔离和明确边界——没做自动加载、没声明类型、没拆离副作用,就谈不上复用。
用 Composer 自动加载规范组织代码结构
不按 psr-4 规范组织命名空间和目录,其他项目根本没法 require 你的组件。Composer 不是可选项,是复用的前提。
- 在
composer.json中严格配置"autoload": {"psr-4": {"MyComponent\": "src/"}},类名必须与文件路径完全对应 -
src/下只放核心逻辑,tests/和examples/平级,不混入业务代码 - 避免在组件里写
require_once __DIR__.'/config.php'这类硬编码路径,配置应由使用者传入
把外部依赖抽象成接口,别直接 new 具体类
一旦组件内部 new PDO() 或 new GuzzleHttpClient(),它就锁死了数据库驱动和 HTTP 客户端,别人想换 Redis 缓存或用 Swoole HTTP 客户端就只能 fork 修改。
- 定义
MyComponentStorageInterface,让使用者传实现,组件只调用save()和fetch() - 构造函数参数必须是接口或标量,禁止默认实例化(如
public function __construct(LoggerInterface $logger = null)可接受null,但不要= new NullLogger()) - 如果真需要默认行为,提供静态工厂方法:
MyComponent::withDefaultStorage(),而不是塞进构造函数
用 PHP 8+ 声明严格类型,别靠文档“约定”
没有 string $id 和 : ?array,别人传个 0 当字符串 ID、传个 false 当配置数组,运行时才报错,根本没法静态分析或 IDE 提示。
立即学习“PHP免费学习笔记(深入)”;
- 所有公共方法必须声明参数类型和返回类型,包括
void和mixed(如果真不确定) - 禁用
@param string $id这类 PHPDoc 类型注释替代真实类型声明 - 数组类型优先用
array{url: string, timeout: int}形式,比array更具表达力
测试用例必须覆盖边界输入和异常流
没测过 null、空字符串、超长字符串、非 UTF-8 字节流的组件,只要被下游项目启用严格错误报告(error_reporting(E_ALL)),第一次调用就可能 fatal error。
- 每个公共方法至少覆盖:正常值、
null、空字符串、非法格式(如传数字给期望 UUID 的string参数) - 用
expectException()显式断言会抛出什么异常,别只写$this->assertTrue(true) - 避免在测试中 mock 全局函数(如
file_get_contents),改用依赖注入 + 接口抽象,否则测试和生产行为不一致
真正难的不是写功能,是决定哪些不该出现在组件里——比如你不该在日志组件里连 MySQL,也不该在分页组件里读取 $_GET。边界划得越清,别人越敢用。



















