HTTP Methods Reference — PHP source
A searchable reference for every HTTP request method - GET, POST, PUT, PATCH, DELETE, and more. See at a glance which are safe, idempotent, and cacheable, then compare any two methods side by side.
This is the PHP implementation — the same logic the interactive tool runs, in a shareable, citable form.
<?php
// Source file: php.php
// Language: PHP (8.1+)
//
// HTTP request-method reference — pure, deterministic data + lookups.
//
// CosmoDev polyglot showcase port of the `http-methods` tool, ported from
// src/lib/http-methods.ts. Functionally equivalent to the TypeScript original:
// identical inputs yield identical outputs (case-insensitive lookup, flag +
// free-text filtering, and a human-readable semantic comparison report).
//
// Property flags (safe / idempotent / cacheable / hasBody) follow RFC 9110
// and the MDN reference table.
//
// Display source — part of CosmoDev's polyglot tool pages.
declare(strict_types=1);
namespace CosmoDev\HttpMethods;
/**
* One HTTP request method and its semantic properties.
*
* Readonly constructor promotion (PHP 8.1) gives immutable, typed records —
* the table is structural and never mutated at runtime.
*/
final class MethodEntry
{
public function __construct(
public readonly string $method,
/** Read-only semantics — no server state change. */
public readonly bool $safe,
/** Repeating the call has the same effect as a single call. */
public readonly bool $idempotent,
/** Responses may be stored by a cache (RFC 9110 / MDN). */
public readonly bool $cacheable,
/** The method conventionally carries a request body. */
public readonly bool $hasBody,
public readonly string $description,
public readonly string $typicalUse,
) {}
}
/**
* Narrowing options for {@see HttpMethods::filter()}.
*
* Boolean fields default to `null` so callers can distinguish "constrain to
* false" from "no constraint" — a tri-state a bare `bool` cannot express.
*/
final class MethodFilter
{
public function __construct(
public readonly ?bool $safe = null,
public readonly ?bool $idempotent = null,
public readonly ?bool $cacheable = null,
/** Free text matched case-insensitively against method, description, typicalUse. */
public readonly ?string $query = null,
) {}
}
/**
* Semantic diff between two methods.
*/
final class MethodComparison
{
/**
* @param bool[] $sameSafety
* @param string[] $differences One sentence per mismatched property.
*/
public function __construct(
public readonly bool $sameSafety,
public readonly bool $sameIdempotence,
public readonly array $differences,
) {}
}
/**
* Canonical table + read-only lookups for the nine HTTP request methods.
*
* Implemented as a static facade over a lazily-built, immutable list — the
* canonical single source of truth that the helpers return references into.
*/
final class HttpMethods
{
/** @return list<MethodEntry> */
public static function all(): array
{
// Built once and cached in a static; the records themselves are readonly.
static $methods = null;
if ($methods === null) {
$methods = [
new MethodEntry('GET', safe: true, idempotent: true, cacheable: true, hasBody: false,
description: 'Retrieves a representation of the target resource; a read-only request.',
typicalUse: 'Fetching a web page, reading an API resource, loading an image.'),
new MethodEntry('POST', safe: false, idempotent: false, cacheable: true, hasBody: true,
description: 'Submits data to be processed, typically creating a new resource or triggering an action.',
typicalUse: 'Submitting a form, creating a record, publishing a message.'),
new MethodEntry('PUT', safe: false, idempotent: true, cacheable: false, hasBody: true,
description: 'Replaces the target resource entirely with the request body.',
typicalUse: 'Updating a full record at a known URL, uploading a file by its path.'),
new MethodEntry('PATCH', safe: false, idempotent: false, cacheable: false, hasBody: true,
description: 'Applies a partial modification to the target resource.',
typicalUse: 'Updating one field of a record, toggling a flag.'),
new MethodEntry('DELETE', safe: false, idempotent: true, cacheable: false, hasBody: false,
description: 'Removes the target resource.',
typicalUse: 'Deleting a record or file by its URL.'),
new MethodEntry('HEAD', safe: true, idempotent: true, cacheable: true, hasBody: false,
description: 'Identical to GET but returns only the response headers, no body.',
typicalUse: 'Checking existence, size, or freshness before downloading.'),
new MethodEntry('OPTIONS', safe: true, idempotent: true, cacheable: false, hasBody: false,
description: 'Describes the communication options for the target resource.',
typicalUse: 'CORS preflight requests, discovering allowed methods.'),
new MethodEntry('CONNECT', safe: false, idempotent: false, cacheable: false, hasBody: false,
description: 'Establishes a tunnel to the server (used with TLS/HTTPS proxies).',
typicalUse: 'Proxying encrypted connections through an intermediary.'),
new MethodEntry('TRACE', safe: true, idempotent: true, cacheable: false, hasBody: false,
description: 'Performs a message loop-back test along the path to the target (debugging only).',
typicalUse: 'Diagnosing request transformations by intermediaries.'),
];
}
return $methods;
}
/**
* Case-insensitive single-method lookup.
*
* @return MethodEntry|null The entry, or null when unknown (the PHP
* analogue of TS's `MethodEntry | null`).
*/
public static function getMethod(string $name): ?MethodEntry
{
$n = strtoupper(trim($name));
foreach (self::all() as $entry) {
if ($entry->method === $n) {
return $entry;
}
}
return null;
}
/**
* Filter the method set by boolean flags and an optional text query.
*
* A method must satisfy every present flag AND, when a query is given,
* match it in at least one of {method, description, typicalUse}.
*
* @return list<MethodEntry>
*/
public static function filter(?MethodFilter $opts = null): array
{
$opts ??= new MethodFilter();
$q = strtolower(trim($opts->query ?? ''));
return array_values(array_filter(self::all(), function (MethodEntry $m) use ($opts, $q): bool {
// Each present flag is an AND constraint; null means skip.
if ($opts->safe !== null && $m->safe !== $opts->safe) {
return false;
}
if ($opts->idempotent !== null && $m->idempotent !== $opts->idempotent) {
return false;
}
if ($opts->cacheable !== null && $m->cacheable !== $opts->cacheable) {
return false;
}
if ($q !== '') {
return str_contains(strtolower($m->method), $q)
|| str_contains(strtolower($m->description), $q)
|| str_contains(strtolower($m->typicalUse), $q);
}
return true;
}));
}
/**
* Compare two methods, surfacing where their semantics agree and differ.
*
* `differences` lists every mismatched property (safe, idempotent,
* cacheable, hasBody) as a human-readable sentence, reproducing the
* canonical phrasing verbatim so output stays identical across ports.
*/
public static function compare(MethodEntry $a, MethodEntry $b): MethodComparison
{
$differences = [];
if ($a->safe !== $b->safe) {
$differences[] = sprintf(
'%s is %s, %s is %s.',
$a->method, self::safeWord($a->safe),
$b->method, self::safeWord($b->safe),
);
}
if ($a->idempotent !== $b->idempotent) {
$differences[] = sprintf(
'%s is %s, %s is %s.',
$a->method, self::idempotentWord($a->idempotent),
$b->method, self::idempotentWord($b->idempotent),
);
}
if ($a->cacheable !== $b->cacheable) {
$differences[] = sprintf(
'%s is %s, %s is %s.',
$a->method, self::cacheableWord($a->cacheable),
$b->method, self::cacheableWord($b->cacheable),
);
}
if ($a->hasBody !== $b->hasBody) {
$differences[] = sprintf(
'%s %s, %s %s.',
$a->method, self::bodyWord($a->hasBody),
$b->method, self::bodyWord($b->hasBody),
);
}
return new MethodComparison(
sameSafety: $a->safe === $b->safe,
sameIdempotence: $a->idempotent === $b->idempotent,
differences: $differences,
);
}
// Phrasing helpers localize the canonical difference-sentence wording so
// the output stays in lock-step across every polyglot port.
private static function safeWord(bool $v): string
{
return $v ? 'safe' : 'not safe';
}
private static function idempotentWord(bool $v): string
{
return $v ? 'idempotent' : 'not idempotent';
}
private static function cacheableWord(bool $v): string
{
return $v ? 'cacheable' : 'not cacheable';
}
private static function bodyWord(bool $v): string
{
return $v ? 'takes a body' : 'does not take a body';
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →