Php 简化嵌套的if语句
我正在实现一个搜索功能,并根据查询参数使用不同的类进行搜索Php 简化嵌套的if语句,php,laravel,Php,Laravel,我正在实现一个搜索功能,并根据查询参数使用不同的类进行搜索 class Search { public function getResults() { if (request('type') == 'thread') { $results = app(SearchThreads::class)->query(); } elseif (request('type') == 'profile_post') {
class Search {
public function getResults()
{
if (request('type') == 'thread') {
$results = app(SearchThreads::class)->query();
} elseif (request('type') == 'profile_post') {
$results = app(SearchProfilePosts::class)->query();
} elseif (request()->missing('type')) {
$results = app(SearchAllPosts::class)->query();
}
}
现在,当我想搜索线程时,我有以下代码
class SearchThreads{
public function query()
{
$searchQuery = request('q');
$onlyTitle = request()->boolean('only_title');
if (isset($searchQuery)) {
if ($onlyTitle) {
$query = Thread::search($searchQuery);
} else {
$query = Threads::search($searchQuery);
}
} else {
if ($onlyTitle) {
$query = Activity::ofThreads();
} else {
$query = Activity::ofThreadsAndReplies();
}
}
}
}
解释代码
如果用户输入搜索词($searchQuery),则使用Algolia进行搜索,否则直接进行数据库查询
- 如果用户输入搜索词
- 如果用户选中了onlyTitle复选框,则使用线程索引
- 如果用户未选中“仅线程”复选框,则使用“线程”索引
- 如果用户未输入搜索词
- 如果用户选中了onlyTitle复选框,则获取所有线程
- 如果用户未选中onlyTitle复选框,则获取所有线程和回复
class Search
{
public function __construct(){
$this->strategy = app(SearchFactory::class)->create();
}
public function getResults()
{
return $this->strategy->search();
}
}
其中,在AlgoliaSearchFactory中创建的类是algolia聚合器,因此可以对这些类中的任何一个调用search方法
像这样的东西会让它更干净还是更糟
现在我有一些策略,这些策略对我来说太难了。我曾尝试为您实现一个好的解决方案,但我不得不对代码做出一些假设 我将请求与构造函数逻辑解耦,并给搜索接口一个请求参数。这使得意图比使用Request函数从稀薄的空气中提取请求更清晰
final class SearchFactory
{
private ContainerInterface $container;
/**
* I am not a big fan of using the container to locate the dependencies.
* If possible I would implement the construction logic inside the methods.
* The only object you would then pass into the constructor are basic building blocks,
* independent from the HTTP request (e.g. PDO, AlgoliaClient etc.)
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
private function databaseSearch(): DatabaseSearch
{
return // databaseSearch construction logic
}
public function thread(): AlgoliaSearch
{
return // thread construction logic
}
public function threads(): AlgoliaSearch
{
return // threads construction logic
}
public function profilePost(): AlgoliaSearch
{
return // thread construction logic
}
public function onlyTitle(): AlgoliaSearch
{
return // thread construction logic
}
public function fromRequest(Request $request): SearchInterface
{
if ($request->missing('q')) {
return $this->databaseSearch();
}
// Fancy solution to reduce if statements in exchange for legibility :)
// Note: this is only a viable solution if you have done correct http validation IMO
$camelCaseType = Str::camel($request->get('type'));
if (!method_exists($this, $camelCaseType)) {
// Throw a relevent error here
}
return $this->$camelCaseType();
}
}
// According to the code you provided, algoliasearch seems an unnecessary wrapper class, which receives a search interface, just to call another search interface. If this is the only reason for its existence, I would remove it
final class AlgoliaSearch implements SearchInterface {
private SearchInterface $search;
public function __construct(SearchInterface $search) {
$this->search = $search;
}
public function search(Request $request): SearchInterface {
return $this->search->search($request);
}
}
我也不确定搜索类的意义。如果它只是有效地将搜索方法重命名为getResults,我不确定重点是什么。这就是为什么我省略了它。我不得不写下所有这些,以使问题变得易懂 SearchFactory获取所有必需的参数,并根据这些参数调用AlgoliaSearchFactory或DatabaseSearchFactory以生成将返回的最终对象
class SearchFactory
{
protected $type;
protected $searchQuery;
protected $onlyTitle;
protected $algoliaSearchFactory;
protected $databaseSearchFactory;
public function __construct(
$type,
$searchQuery,
$onlyTitle,
DatabaseSearchFactory $databaseSearchFactory,
AlgoliaSearchFactory $algoliaSearchFactory
) {
$this->type = $type;
$this->searchQuery = $searchQuery;
$this->onlyTitle = $onlyTitle;
$this->databaseSearchFactory = $databaseSearchFactory;
$this->algoliaSearchFactory = $algoliaSearchFactory;
}
public function create()
{
if (isset($this->searchQuery)) {
return $this->algoliaSearchFactory->create($this->type, $this->onlyTitle);
} else {
return $this->databaseSearchFactory->create($this->type, $this->onlyTitle);
}
}
}
基于从搜索工厂传递的类型和onlyTitle参数的数据库搜索工厂返回一个对象,该对象是获得结果所需使用的最终对象
class DatabaseSearchFactory
{
public function create($type, $onlyTitle)
{
if ($type == 'thread' && !$onlyTitle) {
return app(DatabaseSearchThreads::class);
} elseif ($type == 'profile_post' && !$onlyTitle) {
return app(DatabaseSearchProfilePosts::class);
} elseif ($type == 'thread' && $onlyTitle) {
return app(DatabaseSearchThread::class);
} elseif (is_null($type)) {
return app(DatabaseSearchAllPosts::class);
}
}
}
与DatabaseSearchFactory相同的逻辑
class AlgoliaSearchFactory
{
public function create($type, $onlyTitle)
{
if ($type == 'thread' && !$onlyTitle) {
return app(Threads::class);
} elseif ($type == 'profile_post' && !$onlyTitle) {
return app(ProfilePosts::class);
} elseif (empty($type) && !$onlyTitle) {
return app(AllPosts::class);
} elseif ($onlyTitle) {
return app(Thread::class);
}
}
}
AlgoliaSearchFactory创建的对象有一个方法search,该方法需要一个$searchQuery值
interface AlgoliaSearchInterface
{
public function search($searchQuery);
}
由DatabaseSearchFactory创建的对象具有不需要任何参数的搜索方法
interface DatabaseSearchInterface
{
public function search();
}
类Search现在将SearchFactory生成的最终对象作为参数,它可以实现AlgoliaSearchInterface或DatabaseSearchInterface,这就是为什么我没有输入提示
getResults方法现在必须找出search变量的类型(它实现的接口),以便将$searchQuery作为参数传递或不传递
这就是控制器如何使用搜索类来获得结果。
类搜索
{
受保护的美元战略
public function __construct($search)
{
$this->strategy = $search;
}
public function getResults()
{
if(isset(request('q')))
{
$results = $this->strategy->search(request('q'));
}
else
{
$results = $this->strategy->search();
}
}
}
class SearchController(Search $search)
{
$results = $search->getResults();
}
根据所有@Transitive建议,这就是我想到的。我唯一无法解决的问题是如何在没有if语句的情况下调用getResults方法中的search。我将此代码重构为: 保留请求参数以统一接口中的搜索方法
interface SearchInterface
{
public function search(\Illuminate\Http\Request $request);
}
class Search {
protected $strategy;
public function __construct($search)
{
$this->strategy = $search;
}
public function getResults(\Illuminate\Http\Request $request)
{
return $this->strategy->search($request);
}
}
class SearchFactory
{
private \Illuminate\Contracts\Container\Container $container;
public function __construct(\Illuminate\Contracts\Container\Container $container)
{
$this->container = $container;
}
public function algoliaFromRequest(\Illuminate\Http\Request $request): Search
{
$type = $request['type'];
$onlyTitle = $request->boolean('only_title');
if ($type === 'thread' && !$onlyTitle) {
return $this->container->get(Threads::class);
}
if ($type === 'profile_post' && !$onlyTitle) {
return $this->container->get(ProfilePosts::class);
}
if (empty($type) && !$onlyTitle) {
return $this->container->get(AllPosts::class);
}
if ($onlyTitle) {
return $this->container->get(Thread::class);
}
throw new UnexpectedValueException();
}
public function fromRequest(\Illuminate\Http\Request $request): Search
{
if ($request->missing('q')) {
return $this->databaseFromRequest($request);
}
return $this->algoliaFromRequest($request);
}
public function databaseFromRequest(\Illuminate\Http\Request $request): Search
{
$type = $request['type'];
$onlyTitle = $request->boolean('only_title');
if ($type === 'thread' && !$onlyTitle) {
return $this->container->get(DatabaseSearchThreads::class);
}
if ($type === 'profile_post' && !$onlyTitle) {
return $this->container->get(DatabaseSearchProfilePosts::class);
}
if ($type === 'thread' && $onlyTitle) {
return $this->container->get(DatabaseSearchThread::class);
}
if ($request->missing('type')) {
return $this->container->get(DatabaseSearchAllPosts::class);
}
throw new InvalidArgumentException();
}
}
final class SearchController
{
private SearchFactory $factory;
public function __construct(SearchFactory $factory)
{
$this->factory = $factory;
}
public function listResults(\Illuminate\Http\Request $request)
{
return $this->factory->fromRequest($request)->getResults($request);
}
}
这样做的好处是,不要将请求包含在构造函数中,这一点非常重要。通过这种方式,您可以在应用程序生命周期中创建实例,而无需请求。这有利于缓存、可测试性和模块化。我也不喜欢应用程序和请求方法,因为它们凭空抽取变量,降低了可测试性和性能性能。你能分享更多详细信息吗?这看起来毕竟不是有效的PHP代码。另外,看看奇怪的。这篇文章的第一个版本没有包括任何函数部分-
类搜索{
后面紧接着是if
语句我不清楚问题出在哪里;听起来您对代码有表面上的顾虑?实际上是的,我想避免所有这些if-else语句,并使代码更干净可能是因为我对问题的解释不清楚(我的意思是代码不清楚)。首先,onlyTitle不是由'type'决定的,而是由'only_title'参数决定的。因此,当您调用$request->get('type')时,将不会获得onlyTitle的值,因此将找不到该方法。此外,当给定类型时(例如,该类型='thread')。有两种不同的策略可以基于请求('q')搜索“线程”。如果请求('q')存在,则使用Algolia搜索“线程”,否则使用数据库搜索“线程”。因此,在您的回答中,如果($request->missing('q')){return$this->databaseSearch();},则有以下行($this->databaseSearch();)。当请求('q')),则我必须检查请求(“类型”)以及请求(“仅标题”)的值,以确定搜索策略是的,我将继续检查积极案例,处理它们并立即返回。这样,您只需
interface DatabaseSearchInterface
{
public function search();
}
public function __construct($search)
{
$this->strategy = $search;
}
public function getResults()
{
if(isset(request('q')))
{
$results = $this->strategy->search(request('q'));
}
else
{
$results = $this->strategy->search();
}
}
}
class SearchController(Search $search)
{
$results = $search->getResults();
}
interface SearchInterface
{
public function search(\Illuminate\Http\Request $request);
}
class Search {
protected $strategy;
public function __construct($search)
{
$this->strategy = $search;
}
public function getResults(\Illuminate\Http\Request $request)
{
return $this->strategy->search($request);
}
}
class SearchFactory
{
private \Illuminate\Contracts\Container\Container $container;
public function __construct(\Illuminate\Contracts\Container\Container $container)
{
$this->container = $container;
}
public function algoliaFromRequest(\Illuminate\Http\Request $request): Search
{
$type = $request['type'];
$onlyTitle = $request->boolean('only_title');
if ($type === 'thread' && !$onlyTitle) {
return $this->container->get(Threads::class);
}
if ($type === 'profile_post' && !$onlyTitle) {
return $this->container->get(ProfilePosts::class);
}
if (empty($type) && !$onlyTitle) {
return $this->container->get(AllPosts::class);
}
if ($onlyTitle) {
return $this->container->get(Thread::class);
}
throw new UnexpectedValueException();
}
public function fromRequest(\Illuminate\Http\Request $request): Search
{
if ($request->missing('q')) {
return $this->databaseFromRequest($request);
}
return $this->algoliaFromRequest($request);
}
public function databaseFromRequest(\Illuminate\Http\Request $request): Search
{
$type = $request['type'];
$onlyTitle = $request->boolean('only_title');
if ($type === 'thread' && !$onlyTitle) {
return $this->container->get(DatabaseSearchThreads::class);
}
if ($type === 'profile_post' && !$onlyTitle) {
return $this->container->get(DatabaseSearchProfilePosts::class);
}
if ($type === 'thread' && $onlyTitle) {
return $this->container->get(DatabaseSearchThread::class);
}
if ($request->missing('type')) {
return $this->container->get(DatabaseSearchAllPosts::class);
}
throw new InvalidArgumentException();
}
}
final class SearchController
{
private SearchFactory $factory;
public function __construct(SearchFactory $factory)
{
$this->factory = $factory;
}
public function listResults(\Illuminate\Http\Request $request)
{
return $this->factory->fromRequest($request)->getResults($request);
}
}