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