[英]Tightly coupled dependencies through callback argument types
我的示例使用 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 客户端库。 这个类看起来像这样:
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 的有关失败原因的潜在信息。
有没有办法解决?
是的,解决这个问题的方法是依赖一个与库没有紧密绑定的异常,并且其他替换可以抛出或实现。
幸运的是,Guzzle 就是这种情况。
GuzzleHttp\\Exception\\BadResponseException
扩展了GuzzleHttp\\Exception\\RequestException
,它Psr\\Http\\Message\\RequestInterface\\RequestExceptionInterface
实现了Psr\\Http\\Message\\RequestInterface\\RequestExceptionInterface
;
/**
* Exception when an HTTP error occurs (4xx or 5xx error)
*/
class BadResponseException extends RequestException
{ /** class omitted **}
/**
* HTTP Request exception
*/
class RequestException extends TransferException implements RequestExceptionInterface
{ /** class omitted **}
要正确地对 ecallback 进行类型提示,您可能必须指定Psr\\Http\\Client\\ClientExceptionInterface
,因为这是 PSR 合约中最通用的一个,并且符合要求的实现可能会抛出任何扩展异常: NetworkExceptionInterface
或RequestExceptionInterface
,如前所述。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.