php实现委托
委托模式简介
委托模式是一种对象设计模式,允许一个对象将部分功能交给另一个对象处理。在PHP中可通过接口或魔术方法实现类似功能,常用于事件处理、中间件等场景。
通过接口实现委托
定义接口规范委托对象必须实现的方法,主类持有委托对象引用并调用其方法:
interface TaskDelegate {
public function executeTask(string $data): string;
}
class DelegateImplementation implements TaskDelegate {
public function executeTask(string $data): string {
return "Processed: " . strtoupper($data);
}
}
class MainClass {
private $delegate;
public function __construct(TaskDelegate $delegate) {
$this->delegate = $delegate;
}
public function run(string $input) {
return $this->delegate->executeTask($input);
}
}
// 使用示例
$delegate = new DelegateImplementation();
$main = new MainClass($delegate);
echo $main->run("test data"); // 输出: Processed: TEST DATA
使用魔术方法实现动态委托
通过__call魔术方法实现动态方法转发,适合不确定委托对象方法的场景:
class DynamicDelegate {
public function handleRequest($param) {
return "Dynamic handling: " . $param;
}
}
class Delegator {
private $delegate;
public function __construct($delegate) {
$this->delegate = $delegate;
}
public function __call($method, $args) {
if (method_exists($this->delegate, $method)) {
return call_user_func_array(
[$this->delegate, $method],
$args
);
}
throw new BadMethodCallException("Method {$method} not found");
}
}
// 使用示例
$delegate = new DynamicDelegate();
$proxy = new Delegator($delegate);
echo $proxy->handleRequest('value'); // 输出: Dynamic handling: value
闭包作为委托
PHP的闭包特性可以直接作为可调用委托:
class EventDispatcher {
private $listeners = [];
public function addListener(string $event, callable $handler) {
$this->listeners[$event][] = $handler;
}
public function dispatch(string $event, $data = null) {
foreach ($this->listeners[$event] ?? [] as $handler) {
$handler($data);
}
}
}
// 使用示例
$dispatcher = new EventDispatcher();
$dispatcher->addListener('user.login', function($user) {
echo "User logged in: {$user}\n";
});
$dispatcher->dispatch('user.login', 'admin'); // 输出: User logged in: admin
委托与DI容器结合
在现代框架中常通过依赖注入容器管理委托关系:
interface LoggerInterface {
public function log(string $message);
}
class FileLogger implements LoggerInterface {
public function log(string $message) {
file_put_contents('app.log', $message.PHP_EOL, FILE_APPEND);
}
}
class Service {
private $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function doWork() {
$this->logger->log('Service executed');
}
}
// 容器配置示例(伪代码)
$container->set(LoggerInterface::class, FileLogger::class);
$service = $container->get(Service::class);
$service->doWork(); // 委托FileLogger记录日志
注意事项
- 接口委托需明确定义契约,适合长期稳定的协作关系
- 魔术方法委托更灵活但会牺牲IDE自动补全和类型安全
- 闭包适合一次性简单逻辑,但难以复用和测试
- 委托链不宜过长,避免出现"中间人"代码异味







