【发布时间】:2020-11-19 18:08:51
【问题描述】:
我的示例使用 PHP,但这个概念应该普遍适用于 OOP。
我正在使用依赖注入模式来解耦我的类并允许轻松模拟和测试。对于这个具体示例,我的示例类 ApiConsumer 使用 HTTP 客户端对 API 执行 HTTP 请求,该客户端通过接口注入到构造函数中:
class ApiConsumer {
private $client;
public function __construct(HttpClientInterface $client) {
$this->client = $client;
}
}
interface HttpClientInterface {
public function async(string $method, string $uri, array $options, callable $success, callable $failure): void;
}
现在我的问题是那些回调和参数类型提示(在其他语言中,这将是类型声明的问题)。
接口的一个可能实现是我的类Guzzle,它包装了GuzzleHttp 库,这是一个流行的PHP HTTP 客户端库。这个类看起来像这样:
class Guzzle implements HttpClientInterface {
private $client;
private $promises;
public function __construct() {
$this->client = new GuzzleHttp\Client;
}
public function async(string $method, string $uri, array $options, callable $success, callable $failure): void {
$this->promises[] = function () use ($method, $uri, $options, $success, $failure) {
return $this->client->requestAsync($method, $uri, $options)->then($success, $failure);
};
}
}
因此,它实际上将请求停放在$promises 数组中,直到某个时候,调用另一个实际运行这些请求的方法,根据请求的结果执行成功或失败回调。
这会导致我在编写这些回调函数时出现问题。为了正确地键入提示实际上最终会传递给这些回调的内容,我需要直接引用 GuzzleHttp 库使用的类型。例如,假设我在 ApiConsumer 类中发出 API 请求,如下所示:
public function consumeSomeEndpoint(): void {
$this->client->async(
'GET',
'https://some.api.com/endpoint/',
[],
function (Psr\Http\Message\ResponseInterface $response) {
var_dump($response);
},
function (GuzzleHttp\Exception\BadResponseException $reason) {
echo $reason->getResponse()->getBody();
throw new RuntimeException($reason->getMessage());
},
);
}
ResponseInterface 很好,足够通用,可以在很多地方使用(整个Psr 包本质上只是提供了与 HTTP 相关的接口)。但是,BadResponseException 特定于 GuzzleHttp。如果我想创建HttpClientInterface 的替代实现,我必须实际导入 GuzzleHttp 库,这样我才能理解这些异常。我不能在这里引入接口,因为显然 lib 的 Exceptions 没有实现它。 BadResponseException、Psr\Http\Message\RequestInterface\RequestExceptionInterface 实现的接口不提供用于访问响应负载的getResponse() 方法,该负载包含来自 API 的有关失败原因的潜在信息。
有没有办法解决这个问题?
【问题讨论】:
-
我不能在这里引入接口,因为显然 lib 的异常没有实现它 - 实际上在这种情况下,它们会实现。正是出于这个原因,PSR 提供了
RequestExceptionInterface。
标签: php oop dependency-injection guzzle