diff --git a/src/MessageInterface.php b/src/MessageInterface.php index e9aa34d..28e1821 100644 --- a/src/MessageInterface.php +++ b/src/MessageInterface.php @@ -9,7 +9,7 @@ * * Messages are considered immutable; all methods that might change state MUST * be implemented such that they retain the internal state of the current - * message and return a new instance that contains the changed state. + * message and return an instance that contains the changed state. * * @link http://www.ietf.org/rfc/rfc7230.txt * @link http://www.ietf.org/rfc/rfc7231.txt @@ -26,13 +26,13 @@ interface MessageInterface public function getProtocolVersion(); /** - * Create a new instance with the specified HTTP protocol version. + * Return an instance with the specified HTTP protocol version. * * The version string MUST contain only the HTTP version number (e.g., * "1.1", "1.0"). * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * new protocol version. * * @param string $version HTTP protocol version @@ -41,7 +41,7 @@ public function getProtocolVersion(); public function withProtocolVersion($version); /** - * Retrieves all message headers. + * Retrieves all message header values. * * The keys represent the header name as it will be sent over the wire, and * each value is an array of strings associated with the header. @@ -62,7 +62,8 @@ public function withProtocolVersion($version); * exact case in which headers were originally specified. * * @return array Returns an associative array of the message's headers. Each - * key MUST be a header name, and each value MUST be an array of strings. + * key MUST be a header name, and each value MUST be an array of strings + * for that header. */ public function getHeaders(); @@ -77,44 +78,52 @@ public function getHeaders(); public function hasHeader($name); /** - * Retrieve a header by the given case-insensitive name, as a string. + * Retrieves a message header value by the given case-insensitive name. * - * This method returns all of the header values of the given - * case-insensitive header name as a string concatenated together using - * a comma. + * This method returns an array of all the header values of the given + * case-insensitive header name. * - * NOTE: Not all header values may be appropriately represented using - * comma concatenation. For such headers, use getHeaderLines() instead - * and supply your own delimiter when concatenating. - * - * If the header did not appear in the message, this method should return - * a null value. + * If the header does not appear in the message, this method MUST return an + * empty array. * * @param string $name Case-insensitive header field name. - * @return string|null + * @return string[] An array of string values as provided for the given + * header. If the header does not appear in the message, this method MUST + * return an empty array. */ public function getHeader($name); /** - * Retrieves a header by the given case-insensitive name as an array of strings. - * - * If the header did not appear in the message, this method should return an - * empty array. + * Retrieves the line for a single header, with the header values as a + * comma-separated string. + * + * This method returns all of the header values of the given + * case-insensitive header name as a string concatenated together using + * a comma. + * + * NOTE: Not all header values may be appropriately represented using + * comma concatenation. For such headers, use getHeader() instead + * and supply your own delimiter when concatenating. + * + * If the header does not appear in the message, this method MUST return + * a null value. * * @param string $name Case-insensitive header field name. - * @return string[] + * @return string|null A string of values as provided for the given header + * concatenated together using a comma. If the header does not appear in + * the message, this method MUST return a null value. */ - public function getHeaderLines($name); + public function getHeaderLine($name); /** - * Create a new instance with the provided header, replacing any existing + * Return an instance with the provided header, replacing any existing * values of any headers with the same case-insensitive name. * * While header names are case-insensitive, the casing of the header will * be preserved by this function, and returned from getHeaders(). * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * new and/or updated header and value. * * @param string $name Case-insensitive header field name. @@ -125,7 +134,7 @@ public function getHeaderLines($name); public function withHeader($name, $value); /** - * Creates a new instance, with the specified header appended with the + * Return an instance with the specified header appended with the * given value. * * Existing values for the specified header will be maintained. The new @@ -133,7 +142,7 @@ public function withHeader($name, $value); * exist previously, it will be added. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * new header and/or value. * * @param string $name Case-insensitive header field name to add. @@ -144,12 +153,12 @@ public function withHeader($name, $value); public function withAddedHeader($name, $value); /** - * Creates a new instance, without the specified header. + * Return an instance without the specified header. * * Header resolution MUST be done without case-sensitivity. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that removes + * immutability of the message, and MUST return an instance that removes * the named header. * * @param string $name Case-insensitive header field name to remove. @@ -160,22 +169,22 @@ public function withoutHeader($name); /** * Gets the body of the message. * - * @return StreamableInterface Returns the body as a stream. + * @return StreamInterface Returns the body as a stream. */ public function getBody(); /** - * Create a new instance, with the specified message body. + * Return an instance with the specified message body. * - * The body MUST be a StreamableInterface object. + * The body MUST be a StreamInterface object. * * This method MUST be implemented in such a way as to retain the * immutability of the message, and MUST return a new instance that has the * new body stream. * - * @param StreamableInterface $body Body. + * @param StreamInterface $body Body. * @return self * @throws \InvalidArgumentException When the body is not valid. */ - public function withBody(StreamableInterface $body); + public function withBody(StreamInterface $body); } diff --git a/src/RequestInterface.php b/src/RequestInterface.php index 692c5f4..2c6a2ea 100644 --- a/src/RequestInterface.php +++ b/src/RequestInterface.php @@ -16,7 +16,7 @@ * * Requests are considered immutable; all methods that might change state MUST * be implemented such that they retain the internal state of the current - * message and return a new instance that contains the changed state. + * message and return an instance that contains the changed state. */ interface RequestInterface extends MessageInterface { @@ -28,7 +28,7 @@ interface RequestInterface extends MessageInterface * * This method acts exactly like MessageInterface::getHeaders(), with one * behavioral change: if the Host header has not been previously set, the - * method MUST attempt to pull the host segment of the composed URI, if + * method MUST attempt to pull the host component of the composed URI, if * present. * * @see MessageInterface::getHeaders() @@ -45,12 +45,14 @@ public function getHeaders(); * This method acts exactly like MessageInterface::getHeader(), with * one behavioral change: if the Host header is requested, but has * not been previously set, the method MUST attempt to pull the host - * segment of the composed URI, if present. + * component of the composed URI, if present. * * @see MessageInterface::getHeader() * @see UriInterface::getHost() * @param string $name Case-insensitive header field name. - * @return string + * @return string[] An array of string values as provided for the given + * header. If the header does not appear in the message, this method MUST + * return an empty array. */ public function getHeader($name); @@ -58,19 +60,23 @@ public function getHeader($name); * Extends MessageInterface::getHeaderLines() to provide request-specific * behavior. * - * Retrieves a header by the given case-insensitive name as an array of strings. + * This method returns all of the header values of the given + * case-insensitive header name as a string concatenated together using + * a comma. * * This method acts exactly like MessageInterface::getHeaderLines(), with * one behavioral change: if the Host header is requested, but has * not been previously set, the method MUST attempt to pull the host - * segment of the composed URI, if present. + * component of the composed URI, if present. * - * @see MessageInterface::getHeaderLines() + * @see MessageInterface::getHeaderLine() * @see UriInterface::getHost() * @param string $name Case-insensitive header field name. - * @return string[] + * @return string|null A string of values as provided for the given header + * concatenated together using a comma. If the header does not appear in + * the message, this method MUST return a null value. */ - public function getHeaderLines($name); + public function getHeaderLine($name); /** * Retrieves the message's request target. @@ -91,7 +97,7 @@ public function getHeaderLines($name); public function getRequestTarget(); /** - * Create a new instance with a specific request-target. + * Return an instance with the specific request-target. * * If the request needs a non-origin-form request-target — e.g., for * specifying an absolute-form, authority-form, or asterisk-form — @@ -99,7 +105,7 @@ public function getRequestTarget(); * request-target, verbatim. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * changed request target. * * @link http://tools.ietf.org/html/rfc7230#section-2.7 (for the various @@ -117,14 +123,14 @@ public function withRequestTarget($requestTarget); public function getMethod(); /** - * Create a new instance with the provided HTTP method. + * Return an instance with the provided HTTP method. * * While HTTP method names are typically all uppercase characters, HTTP * method names are case-sensitive and thus implementations SHOULD NOT * modify the given string. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * changed request method. * * @param string $method Case-insensitive method. @@ -145,15 +151,29 @@ public function withMethod($method); public function getUri(); /** - * Create a new instance with the provided URI. + * Returns an instance with the provided URI. + * + * This method will update the Host header of the returned request by + * default if the URI contains a host component. If the URI does not + * contain a host component, any pre-existing Host header will be carried + * over to the returned request. + * + * You can opt-in to preserving the original state of the Host header by + * setting `$preserveHost` to `true`. When `$preserveHost` is set to + * `true`, the returned request will not update the Host header of the + * returned message -- even if the message contains no Host header. This + * means that a call to `getHeader('Host')` on the original request MUST + * equal the return value of a call to `getHeader('Host')` on the returned + * request. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * new UriInterface instance. * * @link http://tools.ietf.org/html/rfc3986#section-4.3 * @param UriInterface $uri New request URI to use. + * @param bool $preserveHost Preserve the original state of the Host header. * @return self */ - public function withUri(UriInterface $uri); + public function withUri(UriInterface $uri, $preserveHost = false); } diff --git a/src/ResponseInterface.php b/src/ResponseInterface.php index a9f0fe1..c2fc025 100644 --- a/src/ResponseInterface.php +++ b/src/ResponseInterface.php @@ -15,35 +15,35 @@ * * Responses are considered immutable; all methods that might change state MUST * be implemented such that they retain the internal state of the current - * message and return a new instance that contains the changed state. + * message and return an instance that contains the changed state. */ interface ResponseInterface extends MessageInterface { /** - * Gets the response Status-Code. + * Gets the response status code. * - * The Status-Code is a 3-digit integer result code of the server's attempt + * The status code is a 3-digit integer result code of the server's attempt * to understand and satisfy the request. * - * @return integer Status code. + * @return int Status code. */ public function getStatusCode(); /** - * Create a new instance with the specified status code, and optionally + * Return an instance with the specified status code, and optionally * reason phrase, for the response. * - * If no Reason-Phrase is specified, implementations MAY choose to default + * If no reason phrase is specified, implementations MAY choose to default * to the RFC 7231 or IANA recommended reason phrase for the response's - * Status-Code. + * status code. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * updated status and reason phrase. * * @link http://tools.ietf.org/html/rfc7231#section-6 * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml - * @param integer $code The 3-digit integer result code to set. + * @param int $code The 3-digit integer result code to set. * @param null|string $reasonPhrase The reason phrase to use with the * provided status code; if none is provided, implementations MAY * use the defaults as suggested in the HTTP specification. @@ -53,13 +53,14 @@ public function getStatusCode(); public function withStatus($code, $reasonPhrase = null); /** - * Gets the response Reason-Phrase, a short textual description of the Status-Code. + * Gets the response reason phrase, a short textual description of the + * status code. * - * Because a Reason-Phrase is not a required element in a response - * Status-Line, the Reason-Phrase value MAY be null. Implementations MAY + * Because a reason phrase is not a required element in a response + * status line, the reason phrase value MAY be null. Implementations MAY * choose to return the default RFC 7231 recommended reason phrase (or those * listed in the IANA HTTP Status Code Registry) for the response's - * Status-Code. + * status code. * * @link http://tools.ietf.org/html/rfc7231#section-6 * @link http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml diff --git a/src/ServerRequestInterface.php b/src/ServerRequestInterface.php index 9739b21..a052841 100644 --- a/src/ServerRequestInterface.php +++ b/src/ServerRequestInterface.php @@ -23,12 +23,12 @@ * - Upload files, if any (as represented by $_FILES) * - Deserialized body parameters (generally from $_POST) * - * $_SERVER and $_FILES values MUST be treated as immutable, as they represent - * application state at the time of request; as such, no methods are provided - * to allow modification of those values. The other values provide such methods, - * as they can be restored from $_SERVER, $_FILES, or the request body, and may - * need treatment during the application (e.g., body parameters may be - * deserialized based on content type). + * $_SERVER values MUST be treated as immutable, as they represent application + * state at the time of request; as such, no methods are provided to allow + * modification of those values. The other values provide such methods, as they + * can be restored from $_SERVER or the request body, and may need treatment + * during the application (e.g., body parameters may be deserialized based on + * content type). * * Additionally, this interface recognizes the utility of introspecting a * request to derive and match additional parameters (e.g., via URI path @@ -38,7 +38,7 @@ * * Requests are considered immutable; all methods that might change state MUST * be implemented such that they retain the internal state of the current - * message and return a new instance that contains the changed state. + * message and return an instance that contains the changed state. */ interface ServerRequestInterface extends RequestInterface { @@ -66,14 +66,14 @@ public function getServerParams(); public function getCookieParams(); /** - * Create a new instance with the specified cookies. + * Return an instance with the specified cookies. * * The data IS NOT REQUIRED to come from the $_COOKIE superglobal, but MUST * be compatible with the structure of $_COOKIE. Typically, this data will * be injected at instantiation. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * updated cookie values. * * @param array $cookies Array of key/value pairs representing cookies. @@ -86,17 +86,17 @@ public function withCookieParams(array $cookies); * * Retrieves the deserialized query string arguments, if any. * - * Note: the query params might not be in sync with the URL or server + * Note: the query params might not be in sync with the URI or server * params. If you need to ensure you are only getting the original - * values, you may need to parse the composed URL or the `QUERY_STRING` - * composed in the server params. + * values, you may need to parse the query string from `getUri()->getQuery()` + * or from the `QUERY_STRING` server param. * * @return array */ public function getQueryParams(); /** - * Create a new instance with the specified query string arguments. + * Return an instance with the specified query string arguments. * * These values SHOULD remain immutable over the course of the incoming * request. They MAY be injected during instantiation, such as from PHP's @@ -106,11 +106,11 @@ public function getQueryParams(); * purposes of how duplicate query parameters are handled, and how nested * sets are handled. * - * Setting query string arguments MUST NOT change the URL stored by the + * Setting query string arguments MUST NOT change the URI stored by the * request, nor the values in the server params. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * updated query string arguments. * * @param array $query Array of query string arguments, typically from @@ -120,18 +120,31 @@ public function getQueryParams(); public function withQueryParams(array $query); /** - * Retrieve the upload file metadata. + * Retrieve normalized file upload data. * - * This method MUST return file upload metadata in the same structure - * as PHP's $_FILES superglobal. + * This method returns upload metadata in a normalized tree, with each leaf + * an instance of Psr\Http\Message\UploadedFileInterface. * - * These values MUST remain immutable over the course of the incoming - * request. They SHOULD be injected during instantiation, such as from PHP's - * $_FILES superglobal, but MAY be derived from other sources. + * These values MAY be prepared from $_FILES or the message body during + * instantiation, or MAY be injected via withUploadedFiles(). * - * @return array Upload file(s) metadata, if any. + * @return array An array tree of UploadedFileInterface instances; an empty + * array MUST be returned if no data is present. */ - public function getFileParams(); + public function getUploadedFiles(); + + /** + * Create a new instance with the specified uploaded files. + * + * This method MUST be implemented in such a way as to retain the + * immutability of the message, and MUST return an instance that has the + * updated body parameters. + * + * @param array An array tree of UploadedFileInterface instances. + * @return self + * @throws \InvalidArgumentException if an invalid structure is provided. + */ + public function withUploadedFiles(array $uploadedFiles); /** * Retrieve any parameters provided in the request body. @@ -151,7 +164,7 @@ public function getFileParams(); public function getParsedBody(); /** - * Create a new instance with the specified body parameters. + * Return an instance with the specified body parameters. * * These MAY be injected during instantiation. * @@ -169,12 +182,14 @@ public function getParsedBody(); * instance with the deserialized parameters. * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * updated body parameters. * * @param null|array|object $data The deserialized body data. This will * typically be in an array or object. * @return self + * @throws \InvalidArgumentException if an unsupported argument type is + * provided. */ public function withParsedBody($data); @@ -209,13 +224,13 @@ public function getAttributes(); public function getAttribute($name, $default = null); /** - * Create a new instance with the specified derived request attribute. + * Return an instance with the specified derived request attribute. * * This method allows setting a single derived request attribute as * described in getAttributes(). * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that has the + * immutability of the message, and MUST return an instance that has the * updated attribute. * * @see getAttributes() @@ -226,14 +241,14 @@ public function getAttribute($name, $default = null); public function withAttribute($name, $value); /** - * Create a new instance that removes the specified derived request + * Return an instance that removes the specified derived request * attribute. * * This method allows removing a single derived request attribute as * described in getAttributes(). * * This method MUST be implemented in such a way as to retain the - * immutability of the message, and MUST return a new instance that removes + * immutability of the message, and MUST return an instance that removes * the attribute. * * @see getAttributes() diff --git a/src/StreamableInterface.php b/src/StreamInterface.php similarity index 80% rename from src/StreamableInterface.php rename to src/StreamInterface.php index 8be1fbc..672ce4d 100644 --- a/src/StreamableInterface.php +++ b/src/StreamInterface.php @@ -3,13 +3,13 @@ namespace Psr\Http\Message; /** - * Describes streamable message body content. + * Describes a data stream. * * Typically, an instance will wrap a PHP stream; this interface provides * a wrapper around the most common operations, including serialization of * the entire stream to a string. */ -interface StreamableInterface +interface StreamInterface { /** * Reads all data from the stream into a string, from the beginning to end. @@ -19,6 +19,10 @@ interface StreamableInterface * * Warning: This could attempt to load a large amount of data into memory. * + * This method MUST NOT raise an exception in order to conform with PHP's + * string casting operations. + * + * @see http://php.net/manual/en/language.oop5.magic.php#object.tostring * @return string */ public function __toString(); @@ -49,7 +53,8 @@ public function getSize(); /** * Returns the current position of the file read/write pointer * - * @return int|bool Position of the file pointer or false on error. + * @return int Position of the file pointer + * @throws \RuntimeException on error. */ public function tell(); @@ -77,20 +82,19 @@ public function isSeekable(); * PHP $whence values for `fseek()`. SEEK_SET: Set position equal to * offset bytes SEEK_CUR: Set position to current location plus offset * SEEK_END: Set position to end-of-stream plus offset. - * @return bool Returns TRUE on success or FALSE on failure. + * @throws \RuntimeException on failure. */ public function seek($offset, $whence = SEEK_SET); /** * Seek to the beginning of the stream. * - * If the stream is not seekable, this method will return FALSE, indicating - * failure; otherwise, it will perform a seek(0), and return the status of - * that operation. + * If the stream is not seekable, this method will raise an exception; + * otherwise, it will perform a seek(0). * * @see seek() * @link http://www.php.net/manual/en/function.fseek.php - * @return bool Returns TRUE on success or FALSE on failure. + * @throws \RuntimeException on failure. */ public function rewind(); @@ -105,8 +109,8 @@ public function isWritable(); * Write data to the stream. * * @param string $string The string that is to be written. - * @return int|bool Returns the number of bytes written to the stream on - * success or FALSE on failure. + * @return int Returns the number of bytes written to the stream. + * @throws \RuntimeException on failure. */ public function write($string); @@ -123,8 +127,9 @@ public function isReadable(); * @param int $length Read up to $length bytes from the object and return * them. Fewer than $length bytes may be returned if underlying stream * call returns fewer bytes. - * @return string|false Returns the data read from the stream, false if - * unable to read or if an error occurs. + * @return string Returns the data read from the stream, or an empty string + * if no bytes are available. + * @throws \RuntimeException if an error occurs. */ public function read($length); @@ -132,6 +137,8 @@ public function read($length); * Returns the remaining contents in a string * * @return string + * @throws \RuntimeException if unable to read or an error occurs while + * reading. */ public function getContents(); diff --git a/src/UploadedFileInterface.php b/src/UploadedFileInterface.php new file mode 100644 index 0000000..7a050d9 --- /dev/null +++ b/src/UploadedFileInterface.php @@ -0,0 +1,115 @@ + * [user-info@]host[:port] @@ -46,40 +54,43 @@ public function getScheme(); * If the port component is not set or is the standard port for the current * scheme, it SHOULD NOT be included. * - * This method MUST return an empty string if no authority information is - * present. - * - * @return string Authority portion of the URI, in "[user-info@]host[:port]" - * format. + * @see https://tools.ietf.org/html/rfc3986#section-3.2 + * @return string The URI authority, in "[user-info@]host[:port]" format. */ public function getAuthority(); /** - * Retrieve the user information portion of the URI, if present. + * Retrieve the user information component of the URI. + * + * If no user information is present, this method MUST return an empty + * string. * * If a user is present in the URI, this will return that value; * additionally, if the password is also present, it will be appended to the * user value, with a colon (":") separating the values. * - * Implementations MUST NOT return the "@" suffix when returning this value. + * The trailing "@" character is not part of the user information and MUST + * NOT be added. * - * @return string User information portion of the URI, if present, in - * "username[:password]" format. + * @return string The URI user information, in "username[:password]" format. */ public function getUserInfo(); /** - * Retrieve the host segment of the URI. + * Retrieve the host component of the URI. * - * This method MUST return a string; if no host segment is present, an - * empty string MUST be returned. + * If no host is present, this method MUST return an empty string. * - * @return string Host segment of the URI. + * The value returned MUST be normalized to lowercase, per RFC 3986 + * Section 3.2.2. + * + * @see http://tools.ietf.org/html/rfc3986#section-3.2.2 + * @return string The URI host. */ public function getHost(); /** - * Retrieve the port segment of the URI. + * Retrieve the port component of the URI. * * If a port is present, and it is non-standard for the current scheme, * this method MUST return it as an integer. If the port is the standard port @@ -91,53 +102,85 @@ public function getHost(); * If no port is present, but a scheme is present, this method MAY return * the standard port for that scheme, but SHOULD return null. * - * @return null|int The port for the URI. + * @return null|int The URI port. */ public function getPort(); /** - * Retrieve the path segment of the URI. + * Retrieve the path component of the URI. + * + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. + * + * Normally, the empty path "" and absolute path "/" are considered equal as + * defined in RFC 7230 Section 2.7.3. But this method MUST NOT automatically + * do this normalization because in contexts with a trimmed base path, e.g. + * the front controller, this difference becomes significant. It's the task + * of the user to handle both "" and "/". + * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.3. * - * This method MUST return a string; if no path is present it MUST return - * the string "/". + * As an example, if the value should include a slash ("/") not intended as + * delimiter between path segments, that value MUST be passed in encoded + * form (e.g., "%2F") to the instance. * - * @return string The path segment of the URI. + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.3 + * @return string The URI path. */ public function getPath(); /** * Retrieve the query string of the URI. * - * This method MUST return a string; if no query string is present, it MUST - * return an empty string. + * If no query string is present, this method MUST return an empty string. * - * The string returned MUST omit the leading "?" character. + * The leading "?" character is not part of the query and MUST NOT be + * added. * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.4. + * + * As an example, if a value in a key/value pair of the query string should + * include an ampersand ("&") not intended as a delimiter between values, + * that value MUST be passed in encoded form (e.g., "%26") to the instance. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.4 * @return string The URI query string. */ public function getQuery(); /** - * Retrieve the fragment segment of the URI. + * Retrieve the fragment component of the URI. * - * This method MUST return a string; if no fragment is present, it MUST - * return an empty string. + * If no fragment is present, this method MUST return an empty string. * - * The string returned MUST omit the leading "#" character. + * The leading "#" character is not part of the fragment and MUST NOT be + * added. * + * The value returned MUST be percent-encoded, but MUST NOT double-encode + * any characters. To determine what characters to encode, please refer to + * RFC 3986, Sections 2 and 3.5. + * + * @see https://tools.ietf.org/html/rfc3986#section-2 + * @see https://tools.ietf.org/html/rfc3986#section-3.5 * @return string The URI fragment. */ public function getFragment(); /** - * Create a new instance with the specified scheme. + * Return an instance with the specified scheme. * * This method MUST retain the state of the current instance, and return - * a new instance that contains the specified scheme. If the scheme - * provided includes the "://" delimiter, it MUST be removed. + * an instance that contains the specified scheme. * - * Implementations SHOULD restrict values to "http", "https", or an empty - * string but MAY accommodate other schemes if required. + * Implementations MUST support the schemes "http" and "https" case + * insensitively, and MAY accommodate other schemes if required. * * An empty scheme is equivalent to removing the scheme. * @@ -148,40 +191,40 @@ public function getFragment(); public function withScheme($scheme); /** - * Create a new instance with the specified user information. + * Return an instance with the specified user information. * * This method MUST retain the state of the current instance, and return - * a new instance that contains the specified user information. + * an instance that contains the specified user information. * * Password is optional, but the user information MUST include the * user; an empty string for the user is equivalent to removing user * information. * - * @param string $user User name to use for authority. - * @param null|string $password Password associated with $user. + * @param string $user The user name to use for authority. + * @param null|string $password The password associated with $user. * @return self A new instance with the specified user information. */ public function withUserInfo($user, $password = null); /** - * Create a new instance with the specified host. + * Return an instance with the specified host. * * This method MUST retain the state of the current instance, and return - * a new instance that contains the specified host. + * an instance that contains the specified host. * * An empty host value is equivalent to removing the host. * - * @param string $host Hostname to use with the new instance. + * @param string $host The hostname to use with the new instance. * @return self A new instance with the specified host. * @throws \InvalidArgumentException for invalid hostnames. */ public function withHost($host); /** - * Create a new instance with the specified port. + * Return an instance with the specified port. * * This method MUST retain the state of the current instance, and return - * a new instance that contains the specified port. + * an instance that contains the specified port. * * Implementations MUST raise an exception for ports outside the * established TCP and UDP port ranges. @@ -189,7 +232,7 @@ public function withHost($host); * A null value provided for the port is equivalent to removing the port * information. * - * @param null|int $port Port to use with the new instance; a null value + * @param null|int $port The port to use with the new instance; a null value * removes the port information. * @return self A new instance with the specified port. * @throws \InvalidArgumentException for invalid ports. @@ -197,19 +240,17 @@ public function withHost($host); public function withPort($port); /** - * Create a new instance with the specified path. + * Return an instance with the specified path. * * This method MUST retain the state of the current instance, and return - * a new instance that contains the specified path. - * - * The path MUST be prefixed with "/"; if not, the implementation MAY - * provide the prefix itself. + * an instance that contains the specified path. * - * The implementation MUST percent-encode reserved characters as - * specified in RFC 3986, Section 2, but MUST NOT double-encode any - * characters. + * The path can either be empty or absolute (starting with a slash) or + * rootless (not starting with a slash). Implementations MUST support all + * three syntaxes. * - * An empty path value is equivalent to removing the path. + * Users can provide both encoded and decoded path characters. + * Implementations ensure the correct encoding as outlined in getPath(). * * @param string $path The path to use with the new instance. * @return self A new instance with the specified path. @@ -218,18 +259,13 @@ public function withPort($port); public function withPath($path); /** - * Create a new instance with the specified query string. + * Return an instance with the specified query string. * * This method MUST retain the state of the current instance, and return - * a new instance that contains the specified query string. + * an instance that contains the specified query string. * - * If the query string is prefixed by "?", that character MUST be removed. - * Additionally, the query string SHOULD be parseable by parse_str() in - * order to be valid. - * - * The implementation MUST percent-encode reserved characters as - * specified in RFC 3986, Section 2, but MUST NOT double-encode any - * characters. + * Users can provide both encoded and decoded query characters. + * Implementations ensure the correct encoding as outlined in getQuery(). * * An empty query string value is equivalent to removing the query string. * @@ -240,33 +276,42 @@ public function withPath($path); public function withQuery($query); /** - * Create a new instance with the specified URI fragment. + * Return an instance with the specified URI fragment. * * This method MUST retain the state of the current instance, and return - * a new instance that contains the specified URI fragment. + * an instance that contains the specified URI fragment. * - * If the fragment is prefixed by "#", that character MUST be removed. + * Users can provide both encoded and decoded fragment characters. + * Implementations ensure the correct encoding as outlined in getFragment(). * * An empty fragment value is equivalent to removing the fragment. * - * @param string $fragment The URI fragment to use with the new instance. - * @return self A new instance with the specified URI fragment. + * @param string $fragment The fragment to use with the new instance. + * @return self A new instance with the specified fragment. */ public function withFragment($fragment); /** - * Return the string representation of the URI. - * - * Concatenates the various segments of the URI, using the appropriate - * delimiters: - * - * - If a scheme is present, "://" MUST append the value. - * - If the authority information is present, that value will be - * concatenated. - * - If a path is present, it MUST be prefixed by a "/" character. - * - If a query string is present, it MUST be prefixed by a "?" character. - * - If a URI fragment is present, it MUST be prefixed by a "#" character. - * + * Return the string representation as a URI reference. + * + * Depending on which components of the URI are present, the resulting + * string is either a full URI or relative reference according to RFC 3985, + * Section 4.1. The method concatenates the various components of the URI, + * using the appropriate delimiters: + * + * - If a scheme is present, it MUST be suffixed by ":". + * - If an authority is present, it MUST be prefixed by "//". + * - The path can be concatenated without delimiters. But there are two + * cases where the path has to be adjusted to make the URI reference + * valid as PHP does not allow to throw an exception in __toString(): + * - If the path is rootless and an authority is present, the path MUST + * be prefixed by "/". + * - If the path is starting with more than one "/" and no authority is + * present, the starting slashes MUST be reduced to one. + * - If a query is present, it MUST be prefixed by "?". + * - If a fragment is present, it MUST be prefixed by "#". + * + * @see http://tools.ietf.org/html/rfc3986#section-4.1 * @return string */ public function __toString();