用于API类实现的PHP/Laravel接口



我有一个带有搜索功能的界面:

interface Searcher
{
public function search($text,$limit)
}

我有一些基于API 的实现

class APISeach implements Searcher
{
public function search($text,$limit)
{
$params = [
'name' => $sName,
'maxRows' => $iLimit,
];
$response = Http::get('http://some_api_service/search', $params)->json();
}
}

我有一些使用这个搜索的代码:

class MyController extends Controller
{
private $seacher;

public function __construct(Searcher $mySeacher)
{
$this->seacher = $mySeacher;
}
public function search($text,$limit=10)
{
$this->seacher->search($text,$limit)
}
}

一切看起来都很好。但如果我需要改变API的实现,它将需要另一个参数。例如:

class AnotherAPISeach implements Searcher
{
public function search($text,$language,$fuzzy,$limit)
{
$ApiObjectFromLib = new ApiObjectFromLib();
$response = $ApiObjectFromLib->search($text,$language,$fuzzy,$limit)->json();
}
}

所以它不能再实现Searcher接口了。API函数是否存在使用接口的方法?所有API都可能需要各种参数,如果我需要更改每个API的接口或控制器代码,那就不好了。

您可以使用可变参数

interface Searcher
{
public function search($text, $limit, ...$additional);
}

如果这违背了interface的目的,则由您决定​​​​​​​

这样的东西(演示)怎么样?

public function search(string $name, int $limit = SearchLimit::DEFAULT)
{
return $this->api->search(
new SearchName($name),
new SearchLimit($limit)
);
}
public function lookup(
string $name,
string $language = SearchLanguage::DEFAULT,
bool $fuzzy = SearchFuzzy::DEFAULT,
int $limit = SearchLimit::DEFAULT
) {
return $this->api->search(
new SearchName($name),
new SearchLanguage($language),
new SearchFuzzy($fuzzy),
new SearchLimit($limit)
);
}

这些";规范";看起来像这样:

namespace Search
{
interface Specification
{
public function __invoke(array $params): array;
}

class Name implements Specification
{
private $name = null;

public function __construct(string $name)
{
$this->name = $name;
}

public function __invoke(array $params): array
{
return [
'name' => $this->name,
];
}
}

class Language implements Specification
{
const DEFAULT = 'en';

private $language = null;

public function __construct(string $language)
{
$this->language = $language;
}

public function __invoke(array $params): array
{
return [
'language' => $this->language ?? 'en',
];
}
}

class Fuzzy implements Specification
{
const DEFAULT = true;

private $fuzzy = null;

public function __construct(bool $fuzzy)
{
$this->fuzzy = $fuzzy;
}

public function __invoke(array $params): array
{
return [
'fuzzy' => $this->fuzzy,
];
}
}

class Limit implements Specification
{
const DEFAULT = 10;

private $max = null;

public function __construct(int $limit)
{
$this->limit = $limit;
}

public function __invoke(array $params): array
{
return [
'maxRows' => $this->limit ?: self::DEFAULT,
];
}
}
}

可搜索的API组成如下:

interface Searchable
{
public function search(SearchSpecification... $criteria);
}
class Search implements Searchable
{
private $url = '/search';

private $defaults = [
'maxRows' => SearchLimit::DEFAULT,
];

public function search(SearchSpecification ...$criteria)
{
return Http::get($this->url, array_reduce(
$criteria,
fn($params, $criteria) => $criteria($params) + $params,
$this->defaults
))->json();
}
}

规范模式很有趣,因为它意味着进入域的请求实际上只是一系列决策,这些决策导致了可以在其他地方应用的配置。

例如,请注意,上面的$criteria($params)对象中的每个对象都被赋予了请求的当前$params,它可以覆盖参数、读取和修改参数,或者可能包含规范检查来验证参数。

注意array + array语法,这是一种合并数组的方法:

['foo' => 'bar'] + ['foo' => 'baz'] // left takes precedence: ['foo' => 'bar']

过滤器/标准非常相似;我倾向于认为那些与它所应用的对象(Repository、Query或Collection)的链接比Specification更紧密,在我看来,Specification更适用于要返回的内容。

最新更新