比如 SlimPHP 中的
Request
實現。
public function withAttribute($name, $value){ $clone = clone $this; $clone->attributes->set($name, $value); return $clone;}
with 的實現都涉及到 clone $object
,clone 就會申請新的變數空間。為什麼不用 set 呢?一個請求過來一個 Request
對象就可以了吧。
public function setAttribute($name, $value){ $this->attributes->set($name, $value); return $this;}
回複內容:
比如 SlimPHP 中的 Request
實現。
public function withAttribute($name, $value){ $clone = clone $this; $clone->attributes->set($name, $value); return $clone;}
with 的實現都涉及到 clone $object
,clone 就會申請新的變數空間。為什麼不用 set 呢?一個請求過來一個 Request
對象就可以了吧。
public function setAttribute($name, $value){ $this->attributes->set($name, $value); return $this;}
好問題!
因為PSR-7
規定,HTTP Message和URI都是值對象(value object
),值對象的一個特徵是它的值決定了它的唯一性,也就是說如果兩個值對象的所有值都是一樣的,那它們也應該是同一個對象;反過來說,如果兩個值對象有至少一個值不一樣,那它們就應該算兩個不同的對象。正因為這個原因,當遵循PSR-7而你要改變Request
一個屬性時,你應該建立另一個對象,而不能在原來的對象上做修改,所以要用clone
而不能簡單地賦值。所以,值對象是一種不可變(immutable
)的對象。
那麼,PSR-7
為什麼要選用不可變的值對象來規範HTTP Message呢?原因有以下幾點:
因為HTTP Message本身就因該是一個不可變的狀態。當一個使用者給你的程式發送請求,發送完成後請求的內容就已經固定,不會再變,只會有下一個相同或不同的請求。
值對象可以儲存原始請求的一切狀態,任何其他的程式都可以獲得這種原始狀態。
官方FIG提供了一段示範值對象好處的代碼:
$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構建其他請求
其實這些在PSR-7的Meta Document中都有說明
http://www.php-fig.org/psr/psr-7/meta/