资讯专栏INFORMATION COLUMN

跟控制器说再见吧,从今天开始使用请求处理器(Request Handlers) 范式

brianway / 3156人阅读

摘要:请求处理器可以理解为仅包含单个动作的控制器,能够使请求到响应的流程更加清晰明确。一个好的使用例子是路由的请求处理在和框架中。控制器的动作被分为多个独立的请求处理器类,分别负责响应单一的动作。您是否应当使用请求处理器替换所有控制器可能不是。

在过去几年中, PHP 开发环境发生了很大的变化。我们开始使用更多更好的设计模式,比如 DRY 和 SOLID) 设计模式原则。但为什么我们仍然在使用控制器?

如果您以前曾经参与过大型项目的架构编写,那么您可能已经注意到迟早会出现控制器过多的这种现象。即使您将控制器逻辑分离到各种类库或服务类中,大量的依赖项和方法以及代码的行数还是会随着时间的推移不断增长。

我来介绍一下请求处理器。这个概念很简单,但很多 PHP 开发人员都不知道。请求处理器可以理解为仅包含单个动作(Action)的控制器,能够使请求到响应的流程更加清晰明确。这个概念与 Paul M. Jones 提出的 Action-Domain-Responder 设计模式有相似之处,后者是MVC模式的替代品。

一个好的方法去建立请求处理器就是使用调用类。可调用类是使用PHP中的魔术方法 __invoke ,把他们变成一个 Callable ,这将允许他们作为函数调用。这里有一个关于调用类的简单例子:

class Greeting
{
    public function __invoke($name)
    {
        echo "Hello " . $name;
    }
}

$welcome = new Greeting();
$welcome("John Doe"); //输出 Hello John Doe

看到这里你大概会想;“我为什么要这样做?”。我知道这是一个有点荒谬的例子。但是它与某些代码一起使用时例如可调用对象和依赖注入,它将变得很有意义。一个好的使用例子是路由的请求处理在Laravel和Slim框架中。

Route::get("/{name}", Greeting::class);

是否让你大吃一惊?没有?让我们把它和你通常写的比较一下:

Route::get("/{name}", "SomeController@greeting");

还没有?除了代码好看之外,还有其他优点。让我们先去看看使用请求处理程序比控制器有那些优点。

单一模式

SOLID 的第一个原则是“单一模式”。在我看来,控制器中存在许多的方法,就打破了这个原则。请求处理程序提供了一个很好的解决方案,可以将这些操作分成它们自己的类,使它们更易于维护,重构和测试。

这是从 UsersController 中提取的2个请求处理程序的示例,它处理用户配置文件的编辑和保存:

class EditUserHandler
{
    public function __construct(
        UserRepository $repository,
        Twig $twig
    ) {
        ...
    }

    public function __invoke(Request $request, Response $response)
    {
        ...
    }
}

class UpdateUserHandler
{
    public function __construct(
        UserRepository $repository,
        UpdateUserValidator $validator,
        ImageManager $resizer,
        Filesystem $storage
    ) {
        ...
    }

    public function __invoke(Request $request, Response $response)
    {
        ...
    }
}

接下来让我们看下一个优势;

测试性能

你最近有没有为你的项目编写过单元测试?在编写单元测试的时候你可能编写了一些与测试无关的模拟依赖项。由于请求处理器将不同的控制器操作拆分为多带带的类,因此您只需注入或绑定该动作所需要的依赖项即可。

这是 Jeffrey Way 的一些建议 Twitter 。

提示:让你的功能测试尽可能更加详细具体,使用测试用例来描述重要的规则和能力。

这基本不会让你的请求处理器都有一个测试文件。对于那些繁琐的控制器测试文件来说是一个非常好的改进。

重构

PhpStorm 和其他的编辑器都有强大的代码重构功能,但是如果你使用的是 Laravel 或者 Slim 框架默认的路由方法将控制器绑定到路由,那么你可能会遇到这种问题。

例如重命名:

Route::get("/{name}", Greeting::class);

比这简单得很多:

Route::get("/{name}", "SomeController@greeting");
结论

请求处理器是控制器很好的替代品。控制器的动作(Actions)被分为多个独立的请求处理器类,分别负责响应单一的动作。这使整个项目的代码更易于维护、重构和测试。

您是否应当使用请求处理器替换所有控制器?可能不是。对于小型应用程序而言,为了简单,将动作组合成控制器或许更加合理。当我开始在 Teamleader 工作后,我才开始发掘请求处理器,我觉得近期没什么换回控制器的必要了。

如果有什么不清楚或有疑问,请在下面留下评论告诉我,我会更新这篇文章。

转自 PHP / Laravel 开发者社区 https://laravel-china.org/top...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/29890.html

相关文章

  • Django搭建个人博客:日志记录

    摘要:每一条日志记录也包含级别,代表对应消息的严重程度。即格式化器,主要功能是确定最终输出的形式和内容。最好是日志能够按自然天进行记录和分割。 上一章学习了自动化测试,很好,现在我们可以绞尽脑汁写出一份全面的测试,来保证代码永远健康了。 话虽如此,但是作为一个独立开发者很难写出真正全面的测试代码。这是因为用户在使用你的网站时可不会循规蹈矩,而是会以各种怪异的姿势浏览网页、上传数据。但这也不是...

    Lowky 评论0 收藏0
  • PHP工程师面试题+笔试题

    摘要:由于协议中没有定义任何状态码,所以除非在某些试验条件下,服务器禁止向此类客户端发送响应。表示要完成请求,需要进一步操作。 最近在广州找工作,大四狗,读着三本前两年刚升二本的学校,文科生,好像一切条件都非常不利,但我还是毅然选择这条路——拍黄片,人不能固步自封,还是要拓展一下自己的知识面,不能只学php而不拓展视野,还是要学学python、java、前端这些面试得有点心塞,各种因为学历被...

    v1 评论0 收藏0
  • Axios源码深度剖析 - AJAX新王者

    摘要:我们先来看看构造函数构造函数就是用来实现拦截器的,这个构造函数原型上有个方法。关于源码,其实是比较简单的,都是用来操作该构造函数的实例属性的。存放拦截器方法,数组内每一项都是有两个属性的对象,两个属性分别对应成功和失败后执行的函数。 Axios源码分析 - XHR篇 文章源码托管在github上,欢迎fork指正! axios 是一个基于 Promise 的http请求库,可以用在浏览...

    DangoSky 评论0 收藏0
  • 从今开始使用javascript的块作用域显式声明

    摘要:尽管如此,由于块作用域的缘故,这段代码还是能够安全地运行。块作用域的显式声明如何避免上述问题呢答案是利用额外的一对大括号来做块作用域的显式声明。 ES2015已经定稿一年多了,想必大家早就用上let和const来充分利用块作用域的优势了吧?那么,你们知道块作用域都是怎么声明的吗? 在各种教程资料的例子里,块作用域都是出现在for(……){……}/if(……){……}/while(……)...

    gaosboy 评论0 收藏0
  • Tornado 简单入门教程(一)——Demo1

    摘要:也就是说用于设定与处理类间的映射关系。在中,默认使用和函数分别处理两种请求。因为表单仍提交到当前页面,所以还是由处理。载入时间相关的的一个类,获取当前时间戳。获取数据库中的名为的。 前面的话 Demo1是一个简单的博客系统(=。=什么网站都叫系统)。我们从这个简单的系统入手,去了解P+T+M网站的内部逻辑,并记住一些规则,方便我们进一步自己开发。 规则这个词特意打上了双引号,目的是...

    solocoder 评论0 收藏0

发表评论

0条评论

brianway

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<