PHPackages                             request-interop/interface - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. request-interop/interface

ActiveLibrary

request-interop/interface
=========================

Interoperable server request interfaces for PHP.

1.x-dev(2mo ago)65031MITPHPPHP &gt;=8.4CI passing

Since Jul 15Pushed 2mo ago3 watchersCompare

[ Source](https://github.com/request-interop/interface)[ Packagist](https://packagist.org/packages/request-interop/interface)[ RSS](/packages/request-interop-interface/feed)WikiDiscussions 1.x Synced 1mo ago

READMEChangelog (2)Dependencies (6)Versions (5)Used By (1)

Request-Interop Standard Interface Package
==========================================

[](#request-interop-standard-interface-package)

Request-Interop provides an interoperable package of standard interfaces for encapsulating readable server-side request values in PHP 8.4 or later, in order to reduce the global mutable state problems that exist with PHP superglobals. It reflects, refines, and reconciles the common practices identified within [several pre-existing projects](./README-RESEARCH.md).

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [BCP 14](https://datatracker.ietf.org/doc/bcp14/) ([RFC 2119](https://datatracker.ietf.org/doc/html/rfc2119), [RFC 8174](https://datatracker.ietf.org/doc/html/rfc8174)).

Interfaces
----------

[](#interfaces)

Request-Interop defines the following interfaces:

- [*RequestStruct*](#requeststruct) represents the current request values and input stream.
- [*RequestStructFactory*](#requeststructfactory) affords creating a new [*RequestStruct*](#requeststruct) instance for the current request.
- [*RequestThrowable*](#requestthrowable) extends [*Throwable*](https://php.net/Throwable) to mark an [*Exception*](https://php.net/Exception) as request-related.
- [*RequestTypeAliases*](#requesttypealiases) provides custom PHPStan types to aid static analysis.

### *RequestStruct*

[](#requeststruct)

[*RequestStruct*](#requeststruct) represents the current request values and input stream.

- Directives:

    - Implementations MUST retain their properties in such way that they remain independent of the superglobal arrays.
- Notes:

    - **The interface defines readable properties, not getter methods.** PHP superglobals are presented as variables and not as functions; using properties instead of methods maintains symmetry with the language. In addition, using things like array access and null-coalesce against a property looks more idiomatic in PHP than with a getter method; it is the difference between `$request->query['foo'] ?? 'bar'` and `$request->getQuery()['foo'] ?? 'bar'` or `$request->query->get('foo', 'bar')`.
    - **The interface defines property hooks for `get` but not `set`.** The interface only guarantees readability; writability is outside the scope of this package.
    - **The properties and the superglobals should be decoupled from each other.** For example, this means that change to `$_GET` should not result in a corresponding change to `$query`. This is to keep the request object free from global mutable state.

#### *RequestStruct* Properties

[](#requeststruct-properties)

- ```
    public request_body_array $body { get; }
    ```

    - Corresponds to a parsed array of the request body content.
    - Directives:

        - Implementations SHOULD populate the property value from a copy of the `$_POST` superglobal array but MAY use some other data source, such as a parsed or decoded representation of the request body.
- ```
    public StreamInterop\Interface\StringableStream $bodyStream { get; }
    ```

    - Corresponds to a stream of the unparsed body content.
    - Directives:

        - Implementations SHOULD use `php://input` as the encapsulated resource but MAY use some other data source.
    - Notes:

        - **This property is a [Stream-Interop](https://github.com/stream-interop/interface) [*StringableStream*](https://github.com/stream-interop/interface#stringablestream).**Although most of the researched projects use a `string` proper for the raw body content, some use a resource. A [*StringableStream*](https://github.com/stream-interop/interface#stringablestream)allows for treating the content as a either a string or a resource stream.
- ```
    public request_cookies_array $cookies { get; }
    ```

    - Corresponds to an array of the request cookie values.
    - Directives:

        - Implementations SHOULD populate the property value from a copy of the `$_COOKIE` superglobal array but MAY use some other data source.
- ```
    public request_headers_array $headers { get; }
    ```

    - Corresponds to an array of the request headers.
    - Directives:

        - Implementations SHOULD derive the property value from the `$server` array but MAY use some other data source.
        - Implementations MUST normalize each header field array key to `lower-kebab-case`.
- ```
    public request_method_string $method { get; }
    ```

    - Corresponds to the request method.
    - Directives:

        - Implementations SHOULD derive the property value from the `$server` array `'REQUEST_METHOD'` value but MAY use some other data source.
- ```
    public request_query_array $query { get; }
    ```

    - Corresponds to an array of the request query values.
    - Directives:

        - Implementations SHOULD populate the property value from a copy of the `$_GET` superglobal array but MAY use some other data source.
    - Notes:

        - **There is no requirement to keep `$query` and `$uri->queryParams`in sync.** Though they may originate from the same source, their values might diverge from each other.
- ```
    public request_server_array $server { get; }
    ```

    - Corresponds to an array of server and execution environment values.
    - Directives:

        - Implementations SHOULD populate the property value from a copy of the `$_SERVER` superglobal array but MAY use some other data source.
- ```
    public upload_structs_array $uploads { get; }
    ```

    - An array of [*UploadStruct*](https://github.com/upload-interop/interface#uploadstruct) instances corresponding to the uploaded files in the request.
    - Directives:

        - Implementations SHOULD derive the property value from the `$_FILES`superglobal array but MAY use some other data source.
    - Notes:

        - **This property is an [Upload-Interop](https://github.com/upload-interop/interface) [`upload_structs_array`](https://github.com/upload-interop/interface#uploadtypealiases).**Thus, `$uploads` takes the place of a `$_FILES` superglobal equivalent.
- ```
    public UriInterop\Interface\UriStruct $uri { get; }
    ```

    - Corresponds to the requested URI.
    - Directives:

        - Implementations SHOULD derive the property value from the `$server` array but MAY use some other data source.
    - Notes:

        - **This property is a [Uri-Interop](https://github.com/uri-interop/interface) [*UriStruct*](https://github.com/uri-interop/interface#uristruct).** Although most of the researched projects use a `string` for the request URI, some use an object. A [*UriStruct*](https://github.com/uri-interop/interface#uristruct) allows for treating the URI as either an object or a string.

### *RequestStructFactory*

[](#requeststructfactory)

[*RequestStructFactory*](#requeststructfactory) affords creating a new [*RequestStruct*](#requeststruct) instance for the current request.

#### *RequestStructFactory* Methods

[](#requeststructfactory-methods)

- ```
    public function newRequest() : RequestStruct;
    ```

    - Creates a new [*RequestStruct*](#requeststruct) instance representing the current request.
    - Directives:

        - Implementations SHOULD create the new [*RequestStruct*](#requeststruct) from the superglobals and `php://input` of the current request, but MAY use some other data source.
        - Implementations SHOULD catch all [*Throwable*](https://php.net/Throwable)s encountered during new [*RequestStruct*](#requeststruct) creation.
        - Implementations SHOULD provide defaults for missing or invalid values discovered during [*RequestStruct*](#requeststruct) creation.
        - Implementations MAY throw a [*RequestThrowable*](#requestthrowable) on failure to create a new [*RequestStruct*](#requeststruct).
    - Notes:

        - **This method should always succeed.** All of the researched implementations always return a new instance, even if they have to provide default values for missing or invalid request elements.

            However, Request-Interop recognizes that there may be times where catastrophic failure is appropriate, thus the allowance for throwing a [*RequestThrowable*](#requestthrowable).

            Consumers should consider failure to create a request object as deserving a 4xx ("Client Error") or 5xx ("Server Error") HTTP response code.

### *RequestThrowable*

[](#requestthrowable)

[*RequestThrowable*](#requestthrowable) extends [*Throwable*](https://php.net/Throwable) to mark an [*Exception*](https://php.net/Exception) as request-related. It adds no class members.

### *RequestTypeAliases*

[](#requesttypealiases)

[*RequestTypeAliases*](#requesttypealiases) provides custom PHPStan types to aid static analysis.

- ```
    request_cookies_array: array

    ```

    - An `array` representing `$_COOKIE` data.
- ```
    request_headers_array: array

    ```

    - An `array` consisting of a header field name string in `lower-kebab-case`and the corresponding header field value string.
- ```
    request_body_array: array

    ```

    - An `array` representing `$_POST` data (or other data parsed or decoded from the request body) up to 16 dimensions.
- ```
    request_method_string: non-empty-string&uppercase-string

    ```

    - A `string` representing the HTTP request method.
- ```
    request_query_array: array

    ```

    - An `array` representing `$_GET` data up to 16 dimensions.
- ```
    request_server_array: array

    ```

    - **The `request_server_array` type is `array` and not `array`.** Some servers add `$_SERVER` keys in mixed case; for example, Microsoft IIS adds `IIS_WasUrlRewritten`.
- Notes:

    - **The `request_query_array` type allows only `string`, while `request_body_array` allows any `scalar`.** The `request_query_array`values correspond to `$_GET`, which is composed only of strings. However, `request_body_array` corresponds to any parsed or decoded form of the request content body; different parsing strategies, such as `json_decode()`, may return various scalar types.
    - **The `*_[00-0F]` types are to enable limited recursion.** PHPStan does not handle recursive type aliases, so `request_body_array` and `request_query_array` cannot ever refer back to themselves. As a result, those type aliases refer to the `*_[00-0F]` types to enable recursion to 16 dimensions. Consumers need not use these recursion-enabling type aliases.

Implementations
---------------

[](#implementations)

Implementations advertised as readonly or immutable MUST be deeply readonly or immutable. With the exception of [*StringableStream*](https://github.com/stream-interop/interface#stringablestream) implementations meeting the specified readonly or immutable conditions, they MUST NOT encapsulate any references, resources, mutable objects, objects or arrays encapsulating references or resources or mutable objects, and so on.

Implementations MAY define additional class members not specified in these interfaces; implementations advertised as readonly or immutable MUST make those additional class members deeply readonly or immutable.

Notes:

- **Reflection does not invalidate advertisements of readonly or immutable implementations.** The ability of a consumer to use Reflection to mutate an implementation advertised as readonly or immutable does not constitute a failure to comply with Request-Interop.
- **Reference implementations** may be found at .

Q &amp; A
---------

[](#q--a)

### Why is *RequestStruct* not identical to a client-side request interface?

[](#why-is-requeststruct-not-identical-to-a-client-side-request-interface)

None of the researched projects model their request objects that way.

A more general answer is from Fowler in *Patterns of Enterprise Application Architecture*(2003, p 21):

> ... I think there is a good distinction to be made between an interface that you provide as a service to others and your use of someone else's service. ... I find it beneficial to think about these differently because the difference in clients alters the way you think about the service.

Request-Interop attempts to model an interface that *uses* a request received from an external source, not one that *provides* a request for sending.

### How is Request-Interop different from PSR-7 *ServerRequestInterface*?

[](#how-is-request-interop-different-from-psr-7-serverrequestinterface)

In short:

- *ServerRequestInterface* attempts to model the incoming HTTP request message, plus application-specific context, with shallow and inconsistent immutability requirements.
- Request-Interop attempts to model the PHP superglobals, provides no space for application context, and requires readonly or immutable implementations to be deeply so.

A longer answer is at [README-PSR-7.md](./README-PSR-7.md).

### How is Request-Interop different from the [Server-Side Request and Response Objects RFC](https://wiki.php.net/rfc/response)?

[](#how-is-request-interop-different-from-the-server-side-request-and-response-objects-rfc)

This package is an intellectual descendant of that RFC, similar in form but much reduced in scope: only the superglobal-equivalent arrays, the method string, the URI, and the uploads properties remain.

### Why is there a separate *RequestStructFactory* ?

[](#why-is-there-a-separate-requeststructfactory-)

Of the 16 researched projects, only 3 provide a separate factory class. The remainder provide either a static factory method on the request object itself, or use only `new` for creating a request object.

However, the Request-Interop request interface is modeled as a struct, meaning it can have no methods, only properties.

As such, even though the use of a factory class is decidedly the minority position, Request-Interop asserts that it is the more suitable choice here.

Further, Request-Interop opines that a separate factory interface better separates the concern of creating or building the *RequestStruct* using the superglobals and related environment elements.

---

###  Health Score

42

—

FairBetter than 90% of packages

Maintenance86

Actively maintained with recent releases

Popularity17

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 84.1% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~118 days

Total

3

Last Release

71d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/25754?v=4)[Paul M. Jones](/maintainers/pmjones)[@pmjones](https://github.com/pmjones)

---

Top Contributors

[![pmjones](https://avatars.githubusercontent.com/u/25754?v=4)](https://github.com/pmjones "pmjones (37 commits)")[![ashnazg](https://avatars.githubusercontent.com/u/100170?v=4)](https://github.com/ashnazg "ashnazg (4 commits)")[![nbish11](https://avatars.githubusercontent.com/u/1518821?v=4)](https://github.com/nbish11 "nbish11 (3 commits)")

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/request-interop-interface/health.svg)

```
[![Health](https://phpackages.com/badges/request-interop-interface/health.svg)](https://phpackages.com/packages/request-interop-interface)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
