为什么 PSR-7 规范中 RequestInterface 中用 withX 而不是 setX

WBOY
Release: 2016-06-06 20:08:31
Original
1156 people have browsed it

比如 SlimPHP 中的 Request 实现。

<code class="php">public function withAttribute($name, $value)
{
    $clone = clone $this;
    $clone->attributes->set($name, $value);
    return $clone;
}</code>
Copy after login
Copy after login

with 的实现都涉及到 clone $object,clone 就会申请新的变量空间。为什么不用 set 呢?一个请求过来一个 Request 对象就可以了吧。

<code class="php">public function setAttribute($name, $value)
{
    $this->attributes->set($name, $value);
    return $this;
}</code>
Copy after login
Copy after login

回复内容:

比如 SlimPHP 中的 Request 实现。

<code class="php">public function withAttribute($name, $value)
{
    $clone = clone $this;
    $clone->attributes->set($name, $value);
    return $clone;
}</code>
Copy after login
Copy after login

with 的实现都涉及到 clone $object,clone 就会申请新的变量空间。为什么不用 set 呢?一个请求过来一个 Request 对象就可以了吧。

<code class="php">public function setAttribute($name, $value)
{
    $this->attributes->set($name, $value);
    return $this;
}</code>
Copy after login
Copy after login

好问题!

因为PSR-7规定,HTTP Message和URI都是值对象(value object),值对象的一个特征是它的值决定了它的唯一性,也就是说如果两个值对象的所有值都是一样的,那它们也应该是同一个对象;反过来说,如果两个值对象有至少一个值不一样,那它们就应该算两个不同的对象。正因为这个原因,当遵循PSR-7而你要改变Request一个属性时,你应该创建另一个对象,而不能在原来的对象上做修改,所以要用clone而不能简单地赋值。所以,值对象是一种不可变(immutable)的对象。

那么,PSR-7为什么要选用不可变的值对象来规范HTTP Message呢?原因有以下几点:

  1. 因为HTTP Message本身就因该是一个不可变的状态。当一个用户给你的程序发送请求,发送完成后请求的内容就已经固定,不会再变,只会有下一个相同或不同的请求。

  2. 值对象可以保存原始请求的一切状态,任何其他的程序都可以获得这种原始状态。

官方FIG提供了一段示范值对象好处的代码:

<code>$uri = new Uri('http://api.example.com');
$baseRequest = new Request($uri, null, [
    'Authorization' => 'Bearer ' . $token,
    'Accept'        => 'application/json',
]);;
//上面构造基础 Request

$request = $baseRequest->withUri($uri->withPath('/user'))->withMethod('GET');
$response = $client->send($request);
//基于上述基础Request构造一个GET请求,获得user的ID

$body = new StringStream(json_encode(['tasks' => [
    'Code',
    'Coffee',
]]));;
$request = $baseRequest
    ->withUri($uri->withPath('/tasks/user/' . $userId))
    ->withMethod('POST')
    ->withHeader('Content-Type', 'application/json')
    ->withBody($body);
$response = $client->send($request)
//基于基础Request构造另一个POST请求,用刚才拿到的user ID添加task
//如果不是使用值对象模型,我们将要重新从头开始构建这个Request


$request = $baseRequest->withUri($uri->withPath('/tasks'))->withMethod('GET');
$response = $client->send($request);
//依然是基于基础Request构建其他请求
</code>
Copy after login

其实这些在PSR-7的Meta Document中都有说明
http://www.php-fig.org/psr/psr-7/meta/

Related labels:
php
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template