Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
9 / 9
CRAP
100.00% covered (success)
100.00%
1 / 1
StatusCode
100.00% covered (success)
100.00%
17 / 17
100.00% covered (success)
100.00%
9 / 9
15
100.00% covered (success)
100.00%
1 / 1
 getCode
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getReasonPhrase
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCategory
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
6
 isInformational
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isSuccess
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isRedirection
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isClientError
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isServerError
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isError
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * This file is part of php-fast-forward/http-message.
7 *
8 * This source file is subject to the license bundled
9 * with this source code in the file LICENSE.
10 *
11 * @copyright Copyright (c) 2025-2026 Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
12 * @license   https://opensource.org/licenses/MIT MIT License
13 *
14 * @see       https://github.com/php-fast-forward/http-message
15 * @see       https://github.com/php-fast-forward
16 * @see       https://datatracker.ietf.org/doc/html/rfc2119
17 */
18
19namespace FastForward\Http\Message;
20
21/**
22 * Enum StatusCode.
23 *
24 * Defines HTTP status codes in accordance with the IETF RFC 9110 and related specifications.
25 * This enum provides a structured representation of common HTTP response codes, grouped by their respective categories:
26 *
27 * - Informational (1xx)
28 * - Successful (2xx)
29 * - Redirection (3xx)
30 * - Client Errors (4xx)
31 * - Server Errors (5xx)
32 *
33 * All status codes MUST adhere to the official HTTP specification and SHALL be used consistently within HTTP responses.
34 */
35enum StatusCode: int
36{
37    // Informational 1xx
38
39    /**
40     * @var int the server has received the request headers and the client SHOULD proceed to send the request body
41     */
42    case Continue = 100;
43
44    /**
45     * @var int the requester has asked the server to switch protocols
46     */
47    case SwitchingProtocols = 101;
48
49    /**
50     * @var int the server has received and is processing the request, but no response is available yet
51     */
52    case Processing = 102;
53
54    /**
55     * @var int used to return some response headers before the final HTTP message
56     */
57    case EarlyHints = 103;
58
59    // Successful 2xx
60
61    /**
62     * @var int the request has succeeded
63     */
64    case Ok = 200;
65
66    /**
67     * @var int the request has been fulfilled and has resulted in the creation of a new resource
68     */
69    case Created = 201;
70
71    /**
72     * @var int the request has been accepted for processing, but the processing has not been completed
73     */
74    case Accepted = 202;
75
76    /**
77     * @var int the request was successful, but the enclosed payload has been modified from that of the origin server
78     */
79    case NonAuthoritativeInformation = 203;
80
81    /**
82     * @var int the server successfully processed the request and is not returning any content
83     */
84    case NoContent = 204;
85
86    /**
87     * @var int the server successfully processed the request, but is not returning any content, and requests that the requester reset the document view
88     */
89    case ResetContent = 205;
90
91    /**
92     * @var int the server is delivering only part of the resource due to a range header sent by the client
93     */
94    case PartialContent = 206;
95
96    /**
97     * @var int the message body that follows is an XML message and can contain a number of separate response codes
98     */
99    case MultiStatus = 207;
100
101    /**
102     * @var int the members of a DAV binding have already been enumerated in a previous reply to this request, and are not being included again
103     */
104    case AlreadyReported = 208;
105
106    /**
107     * @var int the server has fulfilled a request for the resource, and the response is a representation of the result of one or more instance-manipulations
108     */
109    case ImUsed = 226;
110
111    // Redirection 3xx
112
113    /**
114     * @var int indicates multiple options for the resource from which the client may choose
115     */
116    case MultipleChoices = 300;
117
118    /**
119     * @var int this and all future requests SHOULD be directed to the given URI
120     */
121    case MovedPermanently = 301;
122
123    /**
124     * @var int the resource resides temporarily under a different URI
125     */
126    case Found = 302;
127
128    /**
129     * @var int the response to the request can be found under another URI using a GET method
130     */
131    case SeeOther = 303;
132
133    /**
134     * @var int indicates the resource has not been modified since the version specified by the request headers
135     */
136    case NotModified = 304;
137
138    /**
139     * @var int the requested resource is only available through a proxy, whose address is provided in the response
140     */
141    case UseProxy = 305;
142
143    /**
144     * @var int reserved for future use
145     */
146    case Reserved = 306;
147
148    /**
149     * @var int instructs the client to repeat the request with a different URI
150     */
151    case TemporaryRedirect = 307;
152
153    /**
154     * @var int the request and all future requests SHOULD be repeated using another URI
155     */
156    case PermanentRedirect = 308;
157
158    // Client Errors 4xx
159
160    /**
161     * @var int the server cannot process the request due to a client error
162     */
163    case BadRequest = 400;
164
165    /**
166     * @var int authentication is required and has failed or has not yet been provided
167     */
168    case Unauthorized = 401;
169
170    /**
171     * @var int payment is required to access the requested resource
172     */
173    case PaymentRequired = 402;
174
175    /**
176     * @var int the client does not have permission to access the resource
177     */
178    case Forbidden = 403;
179
180    /**
181     * @var int the requested resource could not be found
182     */
183    case NotFound = 404;
184
185    /**
186     * @var int a request method is not supported for the requested resource
187     */
188    case MethodNotAllowed = 405;
189
190    /**
191     * @var int the requested resource is capable of generating only content not acceptable according to the Accept headers
192     */
193    case NotAcceptable = 406;
194
195    /**
196     * @var int proxy authentication is required to access the resource
197     */
198    case ProxyAuthenticationRequired = 407;
199
200    /**
201     * @var int the client did not produce a request within the time that the server was prepared to wait
202     */
203    case RequestTimeout = 408;
204
205    /**
206     * @var int the request could not be completed due to a conflict with the current state of the resource
207     */
208    case Conflict = 409;
209
210    /**
211     * @var int the resource requested is no longer available and will not be available again
212     */
213    case Gone = 410;
214
215    /**
216     * @var int the request did not specify the length of its content, which is required by the requested resource
217     */
218    case LengthRequired = 411;
219
220    /**
221     * @var int the server does not meet one of the preconditions specified by the requester
222     */
223    case PreconditionFailed = 412;
224
225    /**
226     * @var int the request is larger than the server is willing or able to process
227     */
228    case PayloadTooLarge = 413;
229
230    /**
231     * @var int the URI provided was too long for the server to process
232     */
233    case UriTooLong = 414;
234
235    /**
236     * @var int the server does not support the media format of the requested data
237     */
238    case UnsupportedMediaType = 415;
239
240    /**
241     * @var int the client has asked for a portion of the file, but the server cannot supply that portion
242     */
243    case RangeNotSatisfiable = 416;
244
245    /**
246     * @var int the server cannot meet the expectations specified in the Expect request header
247     */
248    case ExpectationFailed = 417;
249
250    /**
251     * @var int this code is returned by HTCPCP-compliant teapots
252     */
253    case ImATeapot = 418;
254
255    /**
256     * @var int the request was directed at a server that is not able to produce a response
257     */
258    case MisdirectedRequest = 421;
259
260    /**
261     * @var int the request was well-formed but was unable to be followed due to semantic errors
262     */
263    case UnprocessableEntity = 422;
264
265    /**
266     * @var int the resource that is being accessed is locked
267     */
268    case Locked = 423;
269
270    /**
271     * @var int the request failed due to failure of a previous request
272     */
273    case FailedDependency = 424;
274
275    /**
276     * @var int indicates the server is unwilling to risk processing a request that might be replayed
277     */
278    case TooEarly = 425;
279
280    /**
281     * @var int The client should switch to a different protocol such as TLS/1.0.
282     */
283    case UpgradeRequired = 426;
284
285    /**
286     * @var int the origin server requires the request to be conditional
287     */
288    case PreconditionRequired = 428;
289
290    /**
291     * @var int the user has sent too many requests in a given amount of time
292     */
293    case TooManyRequests = 429;
294
295    /**
296     * @var int the server is unwilling to process the request because its header fields are too large
297     */
298    case RequestHeaderFieldsTooLarge = 431;
299
300    /**
301     * @var int the requested resource is unavailable for legal reasons
302     */
303    case UnavailableForLegalReasons = 451;
304
305    // Server Errors 5xx
306
307    /**
308     * @var int the server encountered an unexpected condition that prevented it from fulfilling the request
309     */
310    case InternalServerError = 500;
311
312    /**
313     * @var int the server does not support the functionality required to fulfill the request
314     */
315    case NotImplemented = 501;
316
317    /**
318     * @var int the server, while acting as a gateway or proxy, received an invalid response from the upstream server
319     */
320    case BadGateway = 502;
321
322    /**
323     * @var int the server is currently unavailable due to maintenance or overload
324     */
325    case ServiceUnavailable = 503;
326
327    /**
328     * @var int the server did not receive a timely response from an upstream server
329     */
330    case GatewayTimeout = 504;
331
332    /**
333     * @var int the server does not support the HTTP protocol version used in the request
334     */
335    case VersionNotSupported = 505;
336
337    /**
338     * @var int transparent content negotiation for the request results in a circular reference
339     */
340    case VariantAlsoNegotiates = 506;
341
342    /**
343     * @var int the server is unable to store the representation needed to complete the request
344     */
345    case InsufficientStorage = 507;
346
347    /**
348     * @var int the server detected an infinite loop while processing a request
349     */
350    case LoopDetected = 508;
351
352    /**
353     * @var int further extensions to the request are required for the server to fulfill it
354     */
355    case NotExtended = 510;
356
357    /**
358     * @var int the client needs to authenticate to gain network access
359     */
360    case NetworkAuthenticationRequired = 511;
361
362    /**
363     * Returns the numeric HTTP status code.
364     *
365     * @return int the numeric status code as defined by the HTTP specification
366     */
367    public function getCode(): int
368    {
369        return $this->value;
370    }
371
372    /**
373     * Returns a human-readable description of the status code.
374     *
375     * The description is derived from the enum name, replacing underscores with spaces and capitalizing each word.
376     *
377     * @return string the reason phrase corresponding to the status code
378     */
379    public function getReasonPhrase(): string
380    {
381        return preg_replace('/(?<!^)[A-Z]/', ' $0', $this->name);
382    }
383
384    /**
385     * Returns the category of the status code.
386     *
387     * Categories are based on the first digit of the status code:
388     * - 1: Informational
389     * - 2: Success
390     * - 3: Redirection
391     * - 4: Client Error
392     * - 5: Server Error
393     *
394     * @return string
395     */
396    public function getCategory(): string
397    {
398        return match (intdiv($this->value, 100)) {
399            1 => 'Informational',
400            2 => 'Success',
401            3 => 'Redirection',
402            4 => 'Client Error',
403            5 => 'Server Error',
404        };
405    }
406
407    /**
408     * Returns true if the status code is informational (1xx).
409     *
410     * @return bool
411     */
412    public function isInformational(): bool
413    {
414        return 1 === intdiv($this->value, 100);
415    }
416
417    /**
418     * Returns true if the status code indicates success (2xx).
419     *
420     * @return bool
421     */
422    public function isSuccess(): bool
423    {
424        return 2 === intdiv($this->value, 100);
425    }
426
427    /**
428     * Returns true if the status code indicates redirection (3xx).
429     *
430     * @return bool
431     */
432    public function isRedirection(): bool
433    {
434        return 3 === intdiv($this->value, 100);
435    }
436
437    /**
438     * Returns true if the status code indicates a client error (4xx).
439     *
440     * @return bool
441     */
442    public function isClientError(): bool
443    {
444        return 4 === intdiv($this->value, 100);
445    }
446
447    /**
448     * Returns true if the status code indicates a server error (5xx).
449     *
450     * @return bool
451     */
452    public function isServerError(): bool
453    {
454        return 5 === intdiv($this->value, 100);
455    }
456
457    /**
458     * Returns true if the status code indicates any type of error (client or server).
459     *
460     * @return bool
461     */
462    public function isError(): bool
463    {
464        if ($this->isClientError()) {
465            return true;
466        }
467
468        return $this->isServerError();
469    }
470}