HTTP请求/响应对象应该是不可变的吗?


10

我认为可以肯定地说,大多数Web应用程序都基于请求/响应范例。PHP从未对这些对象进行正式的抽象。一个小组正在尝试改变这一点:https : //github.com/php-fig/fig-standards/blob/master/proposed/http-message.md

但是,他们在不变性问题上有些偏颇。一方面,请求/响应对象通常在其生命周期内几乎不需要更改。另一方面,响应对象尤其经常需要添加HTTP标头。

此外,不变性从未真正在PHP领域流行。

人们在使用不可变的请求/响应对象时会看到哪些优势?


假设您要返回一个json对象。

$response = new JsonResponse($item);

漂亮又简单。但是事实证明,该请求是跨域资源共享(CORS)请求。生成响应的代码无关紧要,但是下游的某个过程将添加必要的Access-Control标头。保留原始响应并使用其他标题创建新响应有什么好处?还是严格来说是编程风格的问题。

请求对象更加有趣。它从相同的地方开始:

$request = new Request('incoming request information including uri and headers');

初始信息不需要更改。但是,随着请求的传递,通常需要添加其他处理信息。例如,您可能有一个URL匹配器,该匹配器决定应为给定请求执行什么操作。

$request->setAttribute('action',function() {});

实际执行操作是下游流程的责任。您可能有一个可变的RequestAttributesCollection,它包装了不可变的请求,但在实践中往往有些尴尬。除了属性集合之外,您还可能有一个不变的请求。异常也往往很尴尬。处理此类要求有经验吗?


如果只是您需要的原始请求/响应,我们可以将对象的克隆存储在控制器中,然后再也不会碰到。您可以突变,但仍可以在需要时访问原始文件。这可能是更好的海事组织。
mpen 2015年

Answers:


4

人们在使用不可变的请求/响应对象时会看到哪些优势?

我同意@MainMa的说法:“ 我不确定可读性的微小好处是否会弥补可能的灵活性不足 ”,而且我个人认为强制PHP HTTP Request临时对象或PHP HTTP Response临时对象不可变是任何实际和有用的方面

处理此类要求有经验吗?

  1. Microsoft的Windows Presentation Foundation框架引入了可冻结对象的概念。一旦冻结,这些物体就会变成

    • 不可变的(尝试进行修改时引发异常),
    • 使用起来更快(财产获取者不再需要花哨的“我的价值是什么?”决定),
    • 消耗更少的内存(内部助手数据结构和缓存等可以减少为最节省时间和空间的表示形式)
    • 和共享

    尽管将其用作GUI速度优化,但该概念本身也可以在其他地方应用,包括它的优点

  2. Nancy(“轻量级,低礼仪,用于在.Net和Mono上构建基于HTTP的服务的框架”)在提交注释之一中将不变性的好处描述为

    ...我们可以假设我们的缓存在关闭时是不可变的,这意味着我们没有锁,因此性能更快(尽管命中率不高)...

    我没有找到有关不变性任何其它值得注意的评论,但可重复使用,可缓存响应对象的好处可以申请PHP以及

上面的内容看起来像是题外话的答案,但是我什么都不知道,这就是为什么我认为不变性要求是一个人为的问题,而不是偏好或编码样式等问题。


1
谢谢。这两个答案都是有益的。我决定接受您的想法,因为冻结对象的概念有助于阐明我的想法。创建了一个不变的冻结响应对象get,就像在克隆和取消冻结该对象之前一样。可以添加一堆面向交付的标题(缓存,CORS等)。然后可以将对象冻结并按其方式发送。
塞拉德2015年

7

通常,不可变对象有很多好处。

  • 最重要的是在并行执行的代码中使用不可变对象是多么容易。这也解释了为什么“不变性从未真正在PHP领域流行”

  • 状态一致性更容易获得。

  • 对象很容易,使用起来更自然。

最重要的是,对象在其生命周期中应更改多少-对不可变对象的每次更改都需要创建一个额外的实例,这在内存(以及CPU周期)方面也可能很快变得太昂贵了。这也是为什么大多数string不可变的编程语言最终都会为某种可变字符串(例如StringBuilder在C#中)使用另一类来响应字符串由许多小部分连接在一起(每个部分都是动态添加)的情况。

在客户端库(发送HTTP请求并接收响应)中,使HTTP请求和响应不可变是有意义的:尽管某些请求可以使用流畅的接口构建,但这并不是主要用途。无论如何,响应都不会改变,因此不变性是有道理的。

在服务器端库中(接收HTTP请求并发送响应),虽然请求是不可变的,但我不确定响应是否可以。数据本身可以是一个流(对于某些人(请参阅下文),该流迫使响应对象可变),并且标头本身可以在脚本执行期间“即时”添加,直到响应开始为止。发送给客户端。

在这两种情况下,鉴于都没有并行执行,所以我不确定可读性的微小好处是否可以弥补灵活性的不足。

确保您还阅读了Evert Pot撰写的关于PSR-7更完整的文章。这篇文章解释了,除其他以外,这种不可改变性存在问题的情况之一,是要对较长的响应进行流式传输。就我个人而言,我不明白这一点:恕我直言,没有什么禁止不可变对象包含流(例如,FileReader即使对象读取随时间变化的文件,该对象也可能是不可变的)。对于大响应(或需要花费时间才能生成的响应),Python的Flask框架通过返回迭代器使用了不同的方法


1
值得一提的是IMO的一个优点是,当您拥有不可变的对象时,您无需问自己是否正在使用私有副本,就可以自由更改,也可以自由更改另一个对象拥有的引用,更改可能会影响其他对象。
菲利普

@Philipp:恕我直言,Java.NET的最大缺陷之一是缺乏一种约定,以区分返回对调用者可以随意更改的新对象的引用的方法与返回附加到或封装内部的引用的方法之间的约定可以修改以操纵该状态的状态,以及返回对可能与内部状态连接的对象的引用的状态。在不知道事物应该返回什么样的引用的情况下,不可能编写出健壮和高效的代码,但是并没有约定表明这一点。
2015年

感谢您的回答。它几乎证实了我的想法,因此一定是正确的。我决定接受xmoyxr的回答,因为他提出了冻结我以前从未遇到过的对象的概念。
塞拉德(Cerad)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.