Skip to content

Initialize Client\Response::$reasonPhrase - #19577

Merged
LordSimal merged 1 commit into
5.xfrom
fix-client-response-reason-phrase
Aug 2, 2026
Merged

LordSimal merged 1 commit into
5.xfrom
fix-client-response-reason-phrase

Conversation

@dereuromark

Copy link
Copy Markdown
Member

Fixes #19576.

Cake\Http\Client\Response::$reasonPhrase is assigned in only two places: _parseHeaders(), when a header line matches an HTTP/x.y NNN status line, and withStatus(). Construct a response without a status line and neither runs, so the property stays uninitialized:

$response = new Cake\Http\Client\Response([], 'Okay body.');
$response->getReasonPhrase();
// Error: Typed property Cake\Http\Client\Response::$reasonPhrase
//        must not be accessed before initialization

A method declared : string should not fatal, and PSR-7 requires getReasonPhrase() to return a string.

Defaulting the property to '' is what PSR-7 allows when no reason phrase is known, and matches the reporter's suggestion.

Not a 5.x regression

Worth noting for triage: this is not new. 52104f3 ("Add native type hints for Http properties") changed protected $reasonPhrase; to protected string $reasonPhrase;, but getReasonPhrase(): string already carried the string return type before that commit. So the untyped default was null and the same call raised TypeError: Return value must be of type string, null returned. The typed property only changed the error message.

Left out on purpose

The related inconsistency in the issue thread is not addressed here, since it is a behavior change rather than a fix:

default status default phrase withStatus(404) phrase
Http\Response 200 'OK' 'Not Found'
Http\Client\Response 0 '' (after this PR) ''

Http\Response::_setStatus() fills an empty reason phrase from its $_statusCodes map; the client class has no such map and stores whatever it is given. Making the two consistent would change output for existing withStatus() callers, so it seems better suited to 5.next if wanted at all. Happy to follow up.

`$reasonPhrase` is only assigned in `_parseHeaders()`, when a header line
matches an `HTTP/x.y NNN` status line, and in `withStatus()`. A response
constructed without a status line, such as `new Response([], 'body')` in a
test double, therefore left the property uninitialized and `getReasonPhrase()`
raised "Typed property must not be accessed before initialization" despite
declaring a `string` return type. PSR-7 requires the method to return a
string.

This is not new in 5.x. Before the property gained a native type the untyped
default was null, so the same call raised a TypeError instead.

Default the property to an empty string, which is what PSR-7 allows when no
reason phrase is known.
@dereuromark dereuromark added this to the 5.4.2 milestone Aug 1, 2026
@LordSimal
LordSimal merged commit 85c1fa6 into 5.x Aug 2, 2026
15 checks passed
@LordSimal
LordSimal deleted the fix-client-response-reason-phrase branch August 2, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cake\Http\Client\Response doesn't initialize ::reasonPhrase in all code paths.

3 participants