本文目录导读:

- 函数(Function)
- 类与对象(OOP)
- Trait(特征)
- 命名空间与自动加载
- Composer 与 Packagist(包复用)
- 依赖注入(Dependency Injection)
- include/require(文件包含)
- 服务容器(Service Container)
- 设计模式
- 总结:何时使用哪种复用方式?
在 PHP 中,“复用”指的是重复使用已有的代码、逻辑、类库或组件,以减少重复劳动、提高开发效率和维护性,PHP 提供了多种机制来实现代码复用,从简单的函数到复杂的包管理系统。
以下是 PHP 中实现代码复用的主要方式和最佳实践:
函数(Function)
最基础和直接的复用方式,将一段常用的逻辑封装成函数,在任何需要的地方调用它。
// 定义函数
function formatPrice(float $price): string {
return '¥' . number_format($price, 2);
}
// 复用函数
echo formatPrice(1234.5); // 输出: ¥1,234.50
echo formatPrice(99.99); // 输出: ¥99.99
类与对象(OOP)
面向对象编程是 PHP 中实现复用的核心方式,通过继承、组合和接口实现。
- 继承:子类复用父类的属性和方法。
- 组合:一个类包含另一个类的对象,实现功能复用(优先于继承)。
- 接口:定义契约,实现相同接口的类可以互换使用。
// 基类
class Logger {
public function log(string $message): void {
echo "[LOG]: " . $message . PHP_EOL;
}
}
// 继承复用
class FileLogger extends Logger {
public function log(string $message): void {
// 调用父类方法,再添加额外功能
parent::log("File: " . $message);
}
}
$logger = new FileLogger();
$logger->log("User login"); // 输出: [LOG]: File: User login
Trait(特征)
PHP 是单继承语言,Trait 解决了水平复用的问题,可以在不同类之间复用方法集合,而无需继承。
trait Timestampable {
public function getCreatedAt(): string {
return date('Y-m-d H:i:s', $this->createdAt ?? time());
}
}
class User {
use Timestampable; // 复用 Trait 中的方法
private int $createdAt;
public function __construct() {
$this->createdAt = time();
}
}
$user = new User();
echo $user->getCreatedAt(); // 输出当前时间
命名空间与自动加载
将代码组织到不同的命名空间,并通过 Composer 的自动加载机制实现文件级别的复用。
// src/Utils/StringHelper.php
namespace App\Utils;
class StringHelper {
public static function slugify(string $string): string {
return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $string)));
}
}
// 在任意位置复用
use App\Utils\StringHelper;
echo StringHelper::slugify("Hello World!"); // 输出: hello-world
Composer 与 Packagist(包复用)
PHP 最强大的复用生态,通过 composer.json 安装第三方包(来自 Packagist),或引入自己的私有包。
# 安装一个包(如 monolog 日志库) composer require monolog/monolog
require 'vendor/autoload.php';
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
// 复用 monolog 库的功能
$log = new Logger('name');
$log->pushHandler(new StreamHandler('app.log', Logger::WARNING));
$log->warning('这是一个警告日志');
依赖注入(Dependency Injection)
不是语言特性,而是一种设计模式,通过将依赖对象从外部注入,实现模块的解耦和复用。
class Database {
public function query(string $sql): array {
// 执行查询
return [];
}
}
class UserRepository {
private Database $db;
// 依赖注入:复用任何 Database 实例
public function __construct(Database $db) {
$this->db = $db;
}
public function findUser(int $id) {
return $this->db->query("SELECT * FROM users WHERE id = $id");
}
}
$db = new Database();
$userRepo = new UserRepository($db); // 复用相同的数据库连接
include/require(文件包含)
最原始的复用方式,用于直接包含另一个 PHP 文件。注意:现代 PHP 开发中更推荐使用 Composer 自动加载,而非手动 include。
// config.php
define('DB_HOST', 'localhost');
define('DB_NAME', 'myapp');
// index.php
require_once 'config.php'; // 复用配置
echo DB_HOST;
服务容器(Service Container)
在大型框架(如 Laravel、Symfony)中,通过服务容器管理对象实例的生命周期和依赖,实现高度模块化复用。
// 假设这是 Laravel 的一个服务容器绑定
app()->bind('mailer', function () {
return new MailgunMailer(config('services.mailgun.secret'));
});
// 在任何地方复用 mailer 实例
$mailer = app('mailer');
$mailer->send('你好,这是一封邮件');
设计模式
很多设计模式本身就是为复用而生的,
- 单例模式:复用同一个对象实例。
- 工厂模式:复用创建对象的过程。
- 策略模式:通过接口定义算法族,复用算法。
// 策略模式示例
interface PaymentStrategy {
public function pay(float $amount);
}
class AlipayStrategy implements PaymentStrategy {
public function pay(float $amount) {
echo "使用支付宝支付: $amount";
}
}
class WechatPayStrategy implements PaymentStrategy {
public function pay(float $amount) {
echo "使用微信支付: $amount";
}
}
class Checkout {
public function process(PaymentStrategy $strategy, float $amount) {
$strategy->pay($amount); // 复用支付策略
}
}
何时使用哪种复用方式?
| 复用场景 | 推荐方式 | 说明 |
|---|---|---|
| 简单的通用逻辑 | 函数 | 字符串处理、格式化、数学计算等 |
| 同一类的多个实例 | 类 + 对象 | 用户、订单、数据库连接等 |
| 在不同类之间共享方法 | Trait | 日志、时间戳、权限检查等 |
| 完整的项目/库复用 | Composer 包 | 框架、ORM、模板引擎等 |
| 复用对象创建过程 | 工厂模式/依赖注入 | 解耦对象创建与使用 |
| 复用旧的代码片段 | include/require | 遗留项目,不推荐新项目使用 |
最佳实践建议:
- 优先使用 Composer 管理依赖:不要重复造轮子,使用成熟稳定的第三方包。
- 面向接口编程:依赖抽象而非具体实现,便于替换和测试。
- 偏爱组合而非继承:组合更灵活,继承容易导致层级过深。
- 使用命名空间和 PSR-4 自动加载:保持代码结构清晰,文件自动加载。
- 编写可复用的组件:高内聚、低耦合,单一职责原则。