Lekce 9 - Standardy jazyka PHP - PSR-7 (Rozhraní HTTP zpráv a proudů)
V předchozí lekci, Standardy jazyka PHP - PSR-7 (Obecná specifikace a proudy), jsme se začali věnovat standardu PSR-7, popsali si HTTP zprávy a proudy (streamy).
V lekci PSR-7 jsme se věnovali HTTP zprávám a proudům a dnes si ukážeme, jak bychom s nimi měli správně pracovat.
Psr\Http\Message\MessageInterface
Pod pojmem HTTP zprávy obecně rozumíme požadavek klienta na server a odpověď serveru klientovi. Toto rozhraní definuje metody, které jsou společné oběma typům zpráv.
Zprávy jsou považovány za immutable objekty. Všechny metody, které mohou změnit stav požadavků nebo dotazů musí být implementovány tak, aby ponechaly původní znění a vrátily novou instanci se změněným stavem – NESMÍ tedy přepsat stav původní.
Tohoto rozhraní se také týkají standardy RFC 7230 a RFC 7231.
<?php namespace Psr\Http\Message; interface MessageInterface { public function getProtocolVersion(); /** * @return string */
Vrací verzi HTTP protokolu jako řetězec.
Řetězec MUSÍ obsahovat jenom číslo verze, například „1.1“ nebo „1.0“.
public function withProtocolVersion($version); /** * @param string $version * @return static */
Vrací instanci se zadanou verzí HTTP protokolu.
Řetězec MUSÍ obsahovat jenom číslo verze.
Tato funkce MUSÍ být implementována tak, aby zachovala nezměnitelnost (immutability) zprávy a MUSÍ vracet instanci s novou verzí protokolu.
/** * // Reprezentuje hlavičku jako řetězec * foreach ($message->getHeaders() as $name => $values) { * echo $name . ': ' . implode(', ', $values); * } * * // Iterativně zobrazíme hlavičky * foreach ($message->getHeaders() as $name => $values) { * foreach ($values as $value) { * header(sprintf('%s: %s', $name, $value), false); * } * } * @return string[][] */ public function getHeaders();
Vrací hodnoty všech hlaviček, kde klíče reprezentují názvy hlaviček a každá hodnota je pole řetězců spojených s hlavičkou.
Zatímco názvy hlaviček nejsou case-sensitive, funkce
getHeaders()
zachová původní zápis.
Každý klíč MUSÍ být názvem nějaké hlavičky a každá hodnota MUSÍ být pole řetězců dané hlavičky.
public function hasHeader($name); /** * @param string $name * @return bool */
Funkce hasHeader()
zjistí, jestli se zadaný header ve zprávě
vyskytuje. Argument je opět case-insensitive. Vrací hodnotu true
,
pokud alespoň nějaký header odpovídá argumentu; v opačném případě
vrací hodnotu false
.
public function getHeader($name); /** * @param string $name * @return string[] */
Funkce getHeader()
získá hodnotu headeru. Název zadáváme
opět jako case-insensitive. Vrací pole (v podobě řetězce) pro zadaný
název headeru.
Pokud se header ve zprávě nenachází, funkce MUSÍ vrátit prázdné pole.
public function getHeaderLine($name); /** * @param string $name * @return string */
Funkce getHeaderLine()
vrací všechny hodnoty (jednoho) headeru
oddělené čárkou. Argument $name
musí být zadáván jako
case-insensitive.
Ale pozor! Ne všechny hlavičky mohou být tímto způsobem správně
zřetězeny (např. Set-Cookie
). V těchto případech použijme
raději metodu getHeader()
a při spojování pak i vlastní
oddělovač. Pokud se ve zprávě hlavička nenachází, funkce MUSÍ vrátit
prázdný string
.
public function withHeader($name, $value); /** * @param string $name * @param string|string[] $value // Nová hodnota * @return static * @throws \InvalidArgumentException * // Výjimka pro neplatné argumenty (ať už hodnoty nebo názvy hlaviček) */
Vrací instanci se zadanou hodnotou nahrazující konkrétní header. I když
jsou názvy hlaviček case-insensitive, velikost písmen bude touto funkcí
zachována a může být vrácena pomocí getHeaders()
.
Funkce MUSÍ být implementována tak, aby zachovala nezměnitelnost zprávy a MUSÍ vrátit instanci s novou/aktualizovanou hodnotou.
public function withAddedHeader($name, $value); /* * @param string $name Case-insensitive název * @param string|string[] $value * // Hodnota (hodnoty), které chceme přidat * @return static * @throws \InvalidArgumentException * // Vyhodí výjimku pro neplatný název/hodnoty */
Funkce withAddedHeader()
vrací instanci určité hlavičky, ke
které je přidána další hodnota. Existující hodnoty budou zachovány,
nová bude přidána. Pokud header neexistoval, tak se vytvoří.
Funkce MUSÍ být implementována tak, aby zachovala nezměnitelnost zprávy a MUSÍ vrátit instanci s novou hodnotou/vytvořenou hlavičkou.
public function withoutHeader($name); /* * @param string $name * // Case-insensitive název hlavičky, kterou si přejeme odstranit * @return static */
Vrací instanci bez zadané hlavičky. Rozpoznávání názvů MUSÍ být nezávislé na velikosti písmen.
Funkce MUSÍ být implementována tak, aby zachovala nezměnitelnost zprávy a MUSÍ vrátit instanci bez zadané hlavičky.
public function getBody(); /* * @return StreamInterface */
Získá tělo zprávy a vrací ho jako stream.
public function withBody(StreamInterface $body); /* * Tělo: * @param StreamInterface $body * @return static * V případě neplatného těla vyhodí výjimku: * @throws \InvalidArgumentException */ }
Vrací instanci s předaným tělem zprávy. Tělo MUSÍ být
StreamInterface
objekt.
Funkce MUSÍ být implementována tak, aby zachovala nezměnitelnost zprávy a MUSÍ vrátit instanci, která obsahuje nový stream s tělem.
Psr\Http\Message\StreamInterface
Toto rozhraní popisuje datový proud a poskytuje wrapper pro nejběžnější operace, jakou je třeba serializace celého proudu do řetězce:
<?php namespace Psr\Http\Message; interface StreamInterface { public function __toString(); /** * @return string */
Funkce __toString()
přečte všechna data z proudu od začátku
do konce řetězce.
Funkce se MUSÍ pokusit o vyhledání začátku proudu předtím, než začne číst data a musí číst do té doby, než dojde na konec.
Pozor, použití této funkce může vyústit v uložení velkého množství dat do paměti.
Funkce NESMÍ vyhodit výjimku, pokud provádíme nějakou operaci s řetězci (viz php.net manuál).
public function close(); /** * * @return void */ public function detach(); /** * * @return resource|null * Vrátí zdroj, pokud existuje, jinak null */
Funkce close()
uzavře proud a všechno s ním související.
Druhá funkce oddělí od proudu jakékoliv zdroje s ním související. Po
zavolání funkce je proud dále nepoužitelný.
Další funkce jsou poměrně jednoduché:
public function getSize(); /** * * @return int|null * Vrátí velikost v bytech, pokud je známa, jinak null */ public function tell(); /** * * @return int // Pozice * @throws \RuntimeException * Vyhodí výjimku při výskytu chyby */ public function eof(); /** * * @return bool */
Funkce getSize()
získá velikost proudu, pokud je známa.
Další funkce tell()
vrací aktuální pozici ukazatele čtení
nebo zápisu a funkce eof()
vrací hodnotu true
, pokud
se nacházíme na konci proudu.
public function isSeekable(); /** * @return bool */
Funkce isSeekable()
vrací hodnotu true
nebo
false
podle toho, jestli je proud tzv. seekable. Pojem
seekable znamená, že můžeme sami definovat pozici kurzoru v proudu,
neboli přepsat či číst jakýkoliv byte. Pokud se pokusíme "hledat" mimo
proud, respektive za ním, dojde k jeho prodloužení, tedy např. velikost
souboru se zvětší.
public function seek($offset, $whence = SEEK_SET); /** * @param int $offset * @param int $whence * @throws \RuntimeException */
Funkce seek()
se posune na určenou pozici ve streamu. Parametr
$whence
určuje, jak bude vypočítána pozice kurzoru na základě
offsetu.
Validní hodnoty jsou stejné jako pro známou vestavěnou funkci
fseek()
:
SEEK_SET
: Pozice je rovna offsetu (v bytech)SEEK_CUR
: Pozice je rovna offsetu + aktuální poziceSEEK_END
: Pozice je konec proudu + offset
public function rewind(); /** * @throws \RuntimeException */
Funkce rewind()
přesune ukazatel na začátek proudu. Pokud
proud není seekable, funkce vyhodí výjimku, jinak se provede
seek(0)
(viz funkce výše seek()
a PHP manuál).
public function isWritable(); /** * Určí, jestli do proudu můžeme zapisovat * * @return bool */ public function write($string); /** * Zapíše data do proudu * * @param string $string Řetězec, který chceme zapsat * @return int Počet zapsaných bytů * @throws \RuntimeException */ public function isReadable(); /** * Určí, jestli je proud čitelný * * @return bool */ public function read($length); /** * Přečte data ze streamu * * @param int $length * Přečte až $length bytů z objektu a vrátí je * @return string * Vrátí data nebo prázdný řetězec * @throws \RuntimeException */ public function getContents(); /** * Vrátí zbývající obsah ve streamu * * @return string * @throws \RuntimeException * Pokud nelze stream přečíst, vyhodí výjimku */ public function getMetadata($key = null); /** * @param string $key Specific // Metadata * @return array|mixed|null */ }
Funkce getMetadata()
získá metadata z proudu jako asociativní
pole nebo vrátí specifický klíč. Tyto klíče jsou identické s těmi,
které by vrátila funkce stream_get_meta_data()
. Funkce vrací
asociativní pole, jestliže neposkytneme žádný klíč. Jinak hodnotu
přiřazenou klíči nebo hodnotu null
, pokud klíč není
nalezen.
V další lekci, Standardy jazyka PHP - PSR-7 (Request target a URI), se budeme věnovat další části PSR-7, a to request line, URI a superglobálním proměnným.