From 7b67d3760d9ff97396c2780a484dc0ce4e7cb46b Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Sun, 30 Jun 2019 02:17:18 -0300 Subject: [PATCH 01/11] Add new PSR files. PSR-0 translated. Fixed some erros in PSR-1 file --- .DS_Store | Bin 0 -> 6148 bytes _docs/.DS_Store | Bin 0 -> 6148 bytes _docs/psr/.DS_Store | Bin 0 -> 6148 bytes _docs/psr/PSR-0(Descontinuada).md | 80 +++ _docs/psr/PSR-1-basic-coding-standard.md | 31 +- _docs/psr/PSR-11-container-meta.md | 380 ++++++++++ _docs/psr/PSR-11-container.md | 399 +---------- _docs/psr/PSR-13-links-meta.md | 83 +++ _docs/psr/PSR-13-links.md | 344 +++++++++ _docs/psr/PSR-14-event-dispatcher-meta.md | 216 ++++++ _docs/psr/PSR-14-event-dispatcher.md | 180 +++++ _docs/psr/PSR-15-request-handlers-meta.md | 641 +++++++++++++++++ _docs/psr/PSR-15-request-handlers.md | 668 +----------------- _docs/psr/PSR-16-simple-cache-meta.md | 70 ++ _docs/psr/PSR-16-simple-cache.md | 124 +--- _docs/psr/PSR-17-http-factory-meta.md | 308 +++++++++ _docs/psr/PSR-17-http-factory.md | 219 ++++++ _docs/psr/PSR-18-http-client-meta.md | 148 ++++ _docs/psr/PSR-18-http-client.md | 161 +++++ _docs/psr/PSR-2-coding-style-guide-meta.md | 38 + _docs/psr/PSR-2-coding-style-guide.md | 60 +- _docs/psr/PSR-3-logger-interface.md | 14 +- _docs/psr/PSR-4-autoloader-examples.md | 350 ++++++++++ _docs/psr/PSR-4-autoloader-meta.md | 276 ++++++++ _docs/psr/PSR-4-autoloader.md | 650 +---------------- _docs/psr/PSR-6-cache-meta.md | 336 +++++++++ _docs/psr/PSR-6-cache.md | 352 +--------- _docs/psr/PSR-7-http-message-meta.md | 649 +++++++++++++++++ _docs/psr/PSR-7-http-message.md | 765 ++------------------- _docs/psr/psr-13.md | 5 - 30 files changed, 4590 insertions(+), 2957 deletions(-) create mode 100644 .DS_Store create mode 100644 _docs/.DS_Store create mode 100644 _docs/psr/.DS_Store create mode 100644 _docs/psr/PSR-0(Descontinuada).md create mode 100644 _docs/psr/PSR-11-container-meta.md create mode 100644 _docs/psr/PSR-13-links-meta.md create mode 100644 _docs/psr/PSR-13-links.md create mode 100644 _docs/psr/PSR-14-event-dispatcher-meta.md create mode 100644 _docs/psr/PSR-14-event-dispatcher.md create mode 100644 _docs/psr/PSR-15-request-handlers-meta.md create mode 100644 _docs/psr/PSR-16-simple-cache-meta.md create mode 100644 _docs/psr/PSR-17-http-factory-meta.md create mode 100644 _docs/psr/PSR-17-http-factory.md create mode 100644 _docs/psr/PSR-18-http-client-meta.md create mode 100644 _docs/psr/PSR-18-http-client.md create mode 100644 _docs/psr/PSR-2-coding-style-guide-meta.md create mode 100644 _docs/psr/PSR-4-autoloader-examples.md create mode 100644 _docs/psr/PSR-4-autoloader-meta.md create mode 100644 _docs/psr/PSR-6-cache-meta.md create mode 100644 _docs/psr/PSR-7-http-message-meta.md delete mode 100644 _docs/psr/psr-13.md diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..bc26a8179add0181674e87f30f7ccc5078077989 GIT binary patch literal 6148 zcmeHK%}N6?5Kh{vX+`Wou*Y1y_0Y2ZoP?#;gEwJC4=Q!nEq0-9q`S3fUD?;rH}VO5 z9cPlXv{b>9h|a*|n@naB^6ipI7-PIO44aHq8Djzzu~3HQ6TxxR1u0k$BG+>y!6>;4 z`YKq6CCBe%0KeT5>#&e1cFktL-&=6kkCL>}c;|&;X=!;yh>EDJRW7}r8hNRo4wIHY zILF?xpY{T4pD5Lz+J0~vbw{1*#(|1cKZ?5pog9T-2)Q_m;!urRY8Z!!p2sr-LX<_h zQ>~51j8Ma=f?KsLO3^J) zy+Pbp@eOz<8IwptVt^PR2L1^H_V^R4|75?kO=5r;_&x)8K1fhR*J5r^A05!(^%2KQ zh$vv=TLMv9bS>rvVFZMmR6vu;?GuBWbnr_X=UU7SnsmnX$}o>zncEi%*QTt$g zgVYiO#K1fQMboWf{XhKr{Xd^XJz{_u_)`qdAb3FNBA{uYh8Xx!20j34^HB@{ literal 0 HcmV?d00001 diff --git a/_docs/.DS_Store b/_docs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5c18195b9017b115cb9419c15b4121f6babdfcf8 GIT binary patch literal 6148 zcmeHK%}T>S5Z-O8ZYyFBf<5lVTMsQ!dlEvd2X8_|4=Qa!iVf7HB&kJXC9k1xb*8#u1%*HHbi9h}N{i86=TCI0pDp%IlH-xB(+E(qx9mZ2P^Rh|mc*zx7XI?h+ zjeZ`-qfg!QFT%mJSKm2~qs$AVL86kwU;rW4mthpdQzxE8L8|6)wL^%isP^iOJh!Za zrnIcqtSR$Or`44E*5Pbc6}x-wqtpJ~!(;w5dw$XUa-d(yw!t~Pf?~?McavxoN4GFC zkDf;n5(C5lF+dEg6a(fM5SuGiH5E$?5CcD90QUz84be7OXjEGVba;J6e+3Z*bbL!7 zN`tn+LL+!UxK0JssoXpFI=q-<5Gn)Zfm5T7$61~ z87OPBj_3ag{4z@)`HLxJ5d*})KVyJbx^CBjqRiR)tvozyCA2;?6pSlS0ResC5&#D7 gBMs%$eu+B7*#--ZI17%ebU?ZYC_<H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 **Obsoleto** - A partir de 21-10-2014, o PSR-0 foi marcado como obsoleto. [PSR-4] agora é recomendado +como uma alternativa. + +[PSR-4]: http://www.php-fig.org/psr/psr-4/ +[totalmente-qualificados]: https://www.php.net/manual/pt_BR/language.namespaces.rules.php + +Abaixo estão os requisitos obrigatórios que devem ser cumpridos para interoperabilidade autoloader. + +Obrigatório +----------- + +* Um namespace e classe [totalmente-qualificados] devem ter as seguintes +  estrutura `\\(\)*` +* Cada namespace deve ter um namespace de nível superior ("Vendor Name"). +* Cada namespace pode ter tantos sub-namespaces quanto desejar. +* Cada separador de namespace é convertido em um `SEPARADOR_DE_DIRETORIO` ao + carregar do sistema de arquivos. +* Cada caractere `_` no NOME DA CLASSE é convertido em um `SEPARADOR_DE_DIRETORIO`. + O caractere `_` não tem significado especial no namespace. +* O namespace e a classe totalmente qualificados são sufixados com `.php` ao + carregar do sistema de arquivos. +* Caracteres alfabéticos em vendor names, namespaces e nomes de classes podem + ter qualquer combinação de minúsculas e maiúsculas. + +Exemplos +-------- + +* `\Doctrine\Common\IsolatedClassLoader` => `/path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php` +* `\Symfony\Core\Request` => `/path/to/project/lib/vendor/Symfony/Core/Request.php` +* `\Zend\Acl` => `/path/to/project/lib/vendor/Zend/Acl.php` +* `\Zend\Mail\Message` => `/path/to/project/lib/vendor/Zend/Mail/Message.php` + +Underlines em Namespaces e Nomes de Classes +------------------------------------------- + +* `\namespace\package\Class_Name` => `/path/to/project/lib/vendor/namespace/package/Class/Name.php` +* `\namespace\package_name\Class_Name` => `/path/to/project/lib/vendor/namespace/package_name/Class/Name.php` + +Os padrões que definimos aqui devem ser o menor denominador comum para +interoperabilidade indolor do autoloader. Você pode testar se está +seguindo esses padrões utilizando o exemplo de implementação abaixo da +SplClassLoader que é capaz de carregar classes PHP 5.3 + +Exemplo de Implementação +------------------------ + +Abaixo está uma função para demonstrar o autoloader dos padrões propostos acima. + +~~~php + "users SHOULD NOT pass a container into an object, so the object +> can retrieve *its own dependencies*. Users doing so are using the container as a Service Locator. +> Service Locator usage is generally discouraged." + +```php +// This is not OK, you are using the container as a service locator +class BadExample +{ + public function __construct(ContainerInterface $container) + { + $this->db = $container->get('db'); + } +} + +// Instead, please consider injecting directly the dependencies +class GoodExample +{ + public function __construct($db) + { + $this->db = $db; + } +} +// You can then use the container to inject the $db object into your $goodExample object. +``` + +In the `BadExample` you should not inject the container because: + +- it makes the code **less interoperable**: by injecting the container, you have + to use a container compatible with the Container PSR. With the other + option, your code can work with ANY container. +- you are forcing the developer into naming its entry "db". This naming could + conflict with another package that has the same expectations for another service. +- it is harder to test. +- it is not directly clear from your code that the `BadExample` class will need + the "db" service. Dependencies are hidden. + +Very often, the `ContainerInterface` will be used by other packages. As a end-user +PHP developer using a framework, it is unlikely you will ever need to use containers +or type-hint on the `ContainerInterface` directly. + +Whether using the Container PSR into your code is considered a good practice or not boils down to +knowing if the objects you are retrieving are **dependencies** of the object referencing +the container or not. Here are a few more examples: + +```php +class RouterExample +{ + // ... + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + public function getRoute($request) + { + $controllerName = $this->getContainerEntry($request->getUrl()); + // This is OK, the router is finding the matching controller entry, the controller is + // not a dependency of the router + $controller = $this->container->get($controllerName); + // ... + } +} +``` + +In this example, the router is transforming the URL into a controller entry name, +then fetches the controller from the container. A controller is not really a +dependency of the router. As a rule of thumb, if your object is *computing* +the entry name among a list of entries that can vary, your use case is certainly legitimate. + +As an exception, factory objects whose only purpose is to create and return new instances may use +the service locator pattern. The factory must then implement an interface so that it can itself +be replaced by another factory using the same interface. + +```php +// ok: a factory interface + implementation to create an object +interface FactoryInterface +{ + public function newInstance(); +} + +class ExampleFactory implements FactoryInterface +{ + protected $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + public function newInstance() + { + return new Example($this->container->get('db')); + } +} +``` + +## 5. History + +Before submitting the Container PSR to the PHP-FIG, the `ContainerInterface` was +first proposed in a project named [container-interop](https://github.com/container-interop/container-interop/). +The goal of the project was to provide a test-bed for implementing the `ContainerInterface`, +and to pave the way for the Container PSR. + +In the rest of this meta document, you will see frequent references to +`container-interop.` + +## 6. Interface name + +The interface name is the same as the one discussed for `container-interop` +(only the namespace is changed to match the other PSRs). +It has been thoroughly discussed on `container-interop` [[4]](#link_naming_discussion) and was decided by a vote [[5]](#link_naming_vote). + +The list of options considered with their respective votes are: + +- `ContainerInterface`: +8 +- `ProviderInterface`: +2 +- `LocatorInterface`: 0 +- `ReadableContainerInterface`: -5 +- `ServiceLocatorInterface`: -6 +- `ObjectFactory`: -6 +- `ObjectStore`: -8 +- `ConsumerInterface`: -9 + +## 7. Interface methods + +The choice of which methods the interface would contain was made after a statistical analysis of existing containers. [[6]](#link_statistical_analysis). + +The summary of the analysis showed that: + +- all containers offer a method to get an entry by its id +- a large majority name such method `get()` +- for all containers, the `get()` method has 1 mandatory parameter of type string +- some containers have an optional additional argument for `get()`, but it doesn't have the same purpose between containers +- a large majority of the containers offer a method to test if it can return an entry by its id +- a majority name such method `has()` +- for all containers offering `has()`, the method has exactly 1 parameter of type string +- a large majority of the containers throw an exception rather than returning null when an entry is not found in `get()` +- a large majority of the containers don't implement `ArrayAccess` + +The question of whether to include methods to define entries has been discussed at the very start of the container-interop project [[4]](#link_naming_discussion). +It has been judged that such methods do not belong in the interface described here because it is out of its scope +(see the "Goal" section). + +As a result, the `ContainerInterface` contains two methods: + +- `get()`, returning anything, with one mandatory string parameter. Should throw an exception if the entry is not found. +- `has()`, returning a boolean, with one mandatory string parameter. + +### 7.1. Number of parameters in `get()` method + +While `ContainerInterface` only defines one mandatory parameter in `get()`, it is not incompatible with +existing containers that have additional optional parameters. PHP allows an implementation to offer more parameters +as long as they are optional, because the implementation *does* satisfy the interface. + +Difference with container-interop: [The container-interop spec](https://github.com/container-interop/container-interop/blob/master/docs/ContainerInterface.md) stated that: + +> While `ContainerInterface` only defines one mandatory parameter in `get()`, implementations MAY accept additional optional parameters. + +This sentence was removed from PSR-11 because: + +- It is something that stems from OO principles in PHP, so this is not directly related to PSR-11 +- We do not want to encourage implementors to add additional parameters as we recommend coding against the interface and not the implementation + +However, some implementations have extra optional parameters; that's technically legal. Such implementations are compatible with PSR-11. [[11]](#link_get_optional_parameters) + +### 7.2. Type of the `$id` parameter + +The type of the `$id` parameter in `get()` and `has()` has been discussed in the container-interop project. + +While `string` is used in all the containers that were analyzed, it was suggested that allowing +anything (such as objects) could allow containers to offer a more advanced query API. + +An example given was to use the container as an object builder. The `$id` parameter would then be an +object that would describe how to create an instance. + +The conclusion of the discussion [[7]](#link_method_and_parameters_details) was that this was beyond the scope of getting entries from a container without +knowing how the container provided them, and it was more fit for a factory. + +### 7.3. Exceptions thrown + +This PSR provides 2 interfaces meant to be implemented by container exceptions. + +#### 7.3.1 Base exception + +The `Psr\Container\ContainerExceptionInterface` is the base interface. It SHOULD be implemented by custom exceptions thrown directly by the container. + +It is expected that any exception that is part of the domain of the container implements the `ContainerExceptionInterface`. A few examples: + +- if a container relies on a configuration file and if that configuration file is flawed, the container might throw an `InvalidFileException` implementing the `ContainerExceptionInterface`. +- if a cyclic dependency is detected between dependencies, the container might throw an `CyclicDependencyException` implementing the `ContainerExceptionInterface`. + +However, if the exception is thrown by some code out of the container's scope (for instance an exception thrown while instantiating an entry), the container is not required to wrap this exception in a custom exception implementing the `ContainerExceptionInterface`. + +The usefulness of the base exception interface was questioned: it is not an exception one would typically catch [[8]](#link_base_exception_usefulness). + +However, most PHP-FIG members considered it to be a best practice. Base exception interface are implemented in previous PSRs and several member projects. The base exception interface was therefore kept. + +#### 7.3.2 Not found exception + +A call to the `get` method with a non-existing id must throw an exception implementing the `Psr\Container\NotFoundExceptionInterface`. + +For a given identifier: + +- if the `has` method returns `false`, then the `get` method MUST throw a `Psr\Container\NotFoundExceptionInterface`. +- if the `has` method returns `true`, this does not mean that the `get` method will succeed and throw no exception. It can even throw a `Psr\Container\NotFoundExceptionInterface` if one of the dependencies of the requested entry is missing. + +Therefore, when a user catches the `Psr\Container\NotFoundExceptionInterface`, it has 2 possible meanings [[9]](#link_not_found_behaviour): + +- the requested entry does not exist (bad request) +- or a dependency of the requested entry does not exist (i.e. the container is misconfigured) + +The user can however easily make a distinction with a call to `has`. + +In pseudo-code: + +```php +if (!$container->has($id)) { + // The requested instance does not exist + return; +} +try { + $entry = $container->get($id); +} catch (NotFoundExceptionInterface $e) { + // Since the requested entry DOES exist, a NotFoundExceptionInterface means that the container is misconfigured and a dependency is missing. +} +``` + +## 8. Implementations + +At the time of writing, the following projects already implement and/or consume the `container-interop` version of the interface. + +### Implementors +- [Acclimate](https://github.com/jeremeamia/acclimate-container) +- [Aura.DI](https://github.com/auraphp/Aura.Di) +- [dcp-di](https://github.com/estelsmith/dcp-di) +- [League Container](https://github.com/thephpleague/container) +- [Mouf](http://mouf-php.com) +- [Njasm Container](https://github.com/njasm/container) +- [PHP-DI](http://php-di.org) +- [PimpleInterop](https://github.com/moufmouf/pimple-interop) +- [XStatic](https://github.com/jeremeamia/xstatic) +- [Zend ServiceManager](https://github.com/zendframework/zend-servicemanager) + +### Middleware +- [Alias-Container](https://github.com/thecodingmachine/alias-container) +- [Prefixer-Container](https://github.com/thecodingmachine/prefixer-container) + +### Consumers +- [Behat](https://github.com/Behat/Behat) +- [interop.silex.di](https://github.com/thecodingmachine/interop.silex.di) +- [mindplay/middleman](https://github.com/mindplay-dk/middleman) +- [PHP-DI Invoker](https://github.com/PHP-DI/Invoker) +- [Prophiler](https://github.com/fabfuel/prophiler) +- [Silly](https://github.com/mnapoli/silly) +- [Slim](https://github.com/slimphp/Slim) +- [Splash](http://mouf-php.com/packages/mouf/mvc.splash-common/version/8.0-dev/README.md) +- [Zend Expressive](https://github.com/zendframework/zend-expressive) + +This list is not comprehensive and should be only taken as an example showing that there is considerable interest in the PSR. + +## 9. People + +### 9.1 Editors + +* [Matthieu Napoli](https://github.com/mnapoli) +* [David Négrier](https://github.com/moufmouf) + +### 9.2 Sponsors + +* [Matthew Weier O'Phinney](https://github.com/weierophinney) (Coordinator) +* [Korvin Szanto](https://github.com/KorvinSzanto) + +### 9.3 Contributors + +Are listed here all people that contributed in the discussions or votes (on container-interop and during migration to PSR-11), by alphabetical order: + +* [Alexandru Pătrănescu](https://github.com/drealecs) +* [Amy Stephen](https://github.com/AmyStephen) +* [Ben Peachey](https://github.com/potherca) +* [David Négrier](https://github.com/moufmouf) +* [Don Gilbert](https://github.com/dongilbert) +* [Jason Judge](https://github.com/judgej) +* [Jeremy Lindblom](https://github.com/jeremeamia) +* [Larry Garfield](https://github.com/crell) +* [Marco Pivetta](https://github.com/Ocramius) +* [Matthieu Napoli](https://github.com/mnapoli) +* [Nelson J Morais](https://github.com/njasm) +* [Paul M. Jones](https://github.com/pmjones) +* [Phil Sturgeon](https://github.com/philsturgeon) +* [Stephan Hochdörfer](https://github.com/shochdoerfer) +* [Taylor Otwell](https://github.com/taylorotwell) + +## 10. Relevant links + +1. [Discussion about the container PSR and the service locator](https://groups.google.com/forum/#!topic/php-fig/pyTXRvLGpsw) +1. [Container-interop's `ContainerInterface.php`](https://github.com/container-interop/container-interop/blob/master/src/Interop/Container/ContainerInterface.php) +1. [List of all issues](https://github.com/container-interop/container-interop/issues?labels=ContainerInterface&milestone=&page=1&state=closed) +1. [Discussion about the interface name and container-interop scope](https://github.com/container-interop/container-interop/issues/1) +1. [Vote for the interface name](https://github.com/container-interop/container-interop/wiki/%231-interface-name:-Vote) +1. [Statistical analysis of existing containers method names](https://gist.github.com/mnapoli/6159681) +1. [Discussion about the method names and parameters](https://github.com/container-interop/container-interop/issues/6) +1. [Discussion about the usefulness of the base exception](https://groups.google.com/forum/#!topic/php-fig/_vdn5nLuPBI) +1. [Discussion about the `NotFoundExceptionInterface`](https://groups.google.com/forum/#!topic/php-fig/I1a2Xzv9wN8) +1. Discussion about get optional parameters [in container-interop](https://github.com/container-interop/container-interop/issues/6) and on the [PHP-FIG mailing list](https://groups.google.com/forum/#!topic/php-fig/zY6FAG4-oz8) diff --git a/_docs/psr/PSR-11-container.md b/_docs/psr/PSR-11-container.md index 3532b07..0b51e2b 100644 --- a/_docs/psr/PSR-11-container.md +++ b/_docs/psr/PSR-11-container.md @@ -1,18 +1,4 @@ ---- -title: PRS-11 -category: PSRs -order: 7 ---- - -| Informações Adicionais | -| ---------------------------------------------------| -| [Container interface][Container interface] | -| [Container Meta Document][Container Meta Document] | - -[Container interface]: #Container interface -[Container Meta Document]: #Container Meta Document - -

Container interface

+# Container interface This document describes a common interface for dependency injection containers. @@ -147,386 +133,3 @@ interface NotFoundExceptionInterface extends ContainerExceptionInterface { } ~~~ - - -

Container Meta Document

- -## 1. Introduction - -This document describes the process and discussions that led to the Container PSR. -Its goal is to explain the reasons behind each decision. - -## 2. Why bother? - -There are dozens of dependency injection containers out there, and these -DI containers have very different ways to store entries. - -- Some are based on callbacks (Pimple, Laravel, ...) -- Others are based on configuration (Symfony, ZF, ...), with various formats - (PHP arrays, YAML files, XML files...) -- Some can leverage factories... -- Some have a PHP API to build entries (PHP-DI, ZF, Symfony, Mouf...) -- Some can do auto-wiring (Laravel, PHP-DI, ...) -- Others can wire entries based on annotations (PHP-DI, JMS Bundle...) -- Some have a graphical user interface (Mouf...) -- Some can compile configuration files to PHP classes (Symfony, ZF...) -- Some can do aliasing... -- Some can use proxies to provide lazy loading of dependencies... - -So when you look at the big picture, there is a very large number of ways in -which the DI problem can be tackled, and therefore a big number of different -implementations. However, all the DI containers out there are answering the -same need: they offer a way for the application to retrieve a set of -configured objects (usually services). - -By standardizing the way entries are fetched from a container, frameworks and -libraries using the Container PSR could work with any compatible container. -That would allow end users to choose their own container based on their own preferences. - -## 3. Scope -### 3.1. Goals - -The goal set by the Container PSR is to standardize how frameworks and libraries make use of a -container to obtain objects and parameters. - -It is important to distinguish the two usages of a container: - -- configuring entries -- fetching entries - -Most of the time, those two sides are not used by the same party. -While it is often end users who tend to configure entries, it is generally the framework that fetches -entries to build the application. - -This is why this interface focuses only on how entries can be fetched from a container. - -### 3.2. Non-goals - -How entries are set in the container and how they are configured is out of the -scope of this PSR. This is what makes a container implementation unique. Some -containers have no configuration at all (they rely on autowiring), others rely -on PHP code defined via callback, others on configuration files... This standard -only focuses on how entries are fetched. - -Also, naming conventions used for entries are not part of the scope of this -PSR. Indeed, when you look at naming conventions, there are 2 strategies: - -- the identifier is the class name, or an interface name (used mostly - by frameworks with an autowiring capability) -- the identifier is a common name (closer to a variable name), which is - mostly used by frameworks relying on configuration. - -Both strategies have their strengths and weaknesses. The goal of this PSR -is not to choose one convention over the other. Instead, the user can simply -use aliasing to bridge the gap between 2 containers with different naming strategies. - -## 4. Recommended usage: Container PSR and the Service Locator - -The PSR states that: - -> "users SHOULD NOT pass a container into an object, so the object -> can retrieve *its own dependencies*. Users doing so are using the container as a Service Locator. -> Service Locator usage is generally discouraged." - -```php -// This is not OK, you are using the container as a service locator -class BadExample -{ - public function __construct(ContainerInterface $container) - { - $this->db = $container->get('db'); - } -} - -// Instead, please consider injecting directly the dependencies -class GoodExample -{ - public function __construct($db) - { - $this->db = $db; - } -} -// You can then use the container to inject the $db object into your $goodExample object. -``` - -In the `BadExample` you should not inject the container because: - -- it makes the code **less interoperable**: by injecting the container, you have - to use a container compatible with the Container PSR. With the other - option, your code can work with ANY container. -- you are forcing the developer into naming its entry "db". This naming could - conflict with another package that has the same expectations for another service. -- it is harder to test. -- it is not directly clear from your code that the `BadExample` class will need - the "db" service. Dependencies are hidden. - -Very often, the `ContainerInterface` will be used by other packages. As a end-user -PHP developer using a framework, it is unlikely you will ever need to use containers -or type-hint on the `ContainerInterface` directly. - -Whether using the Container PSR into your code is considered a good practice or not boils down to -knowing if the objects you are retrieving are **dependencies** of the object referencing -the container or not. Here are a few more examples: - -```php -class RouterExample -{ - // ... - - public function __construct(ContainerInterface $container) - { - $this->container = $container; - } - - public function getRoute($request) - { - $controllerName = $this->getContainerEntry($request->getUrl()); - // This is OK, the router is finding the matching controller entry, the controller is - // not a dependency of the router - $controller = $this->container->get($controllerName); - // ... - } -} -``` - -In this example, the router is transforming the URL into a controller entry name, -then fetches the controller from the container. A controller is not really a -dependency of the router. As a rule of thumb, if your object is *computing* -the entry name among a list of entries that can vary, your use case is certainly legitimate. - -As an exception, factory objects whose only purpose is to create and return new instances may use -the service locator pattern. The factory must then implement an interface so that it can itself -be replaced by another factory using the same interface. - -```php -// ok: a factory interface + implementation to create an object -interface FactoryInterface -{ - public function newInstance(); -} - -class ExampleFactory implements FactoryInterface -{ - protected $container; - - public function __construct(ContainerInterface $container) - { - $this->container = $container; - } - - public function newInstance() - { - return new Example($this->container->get('db')); - } -} -``` - -## 5. History - -Before submitting the Container PSR to the PHP-FIG, the `ContainerInterface` was -first proposed in a project named [container-interop](https://github.com/container-interop/container-interop/). -The goal of the project was to provide a test-bed for implementing the `ContainerInterface`, -and to pave the way for the Container PSR. - -In the rest of this meta document, you will see frequent references to -`container-interop.` - -## 6. Interface name - -The interface name is the same as the one discussed for `container-interop` -(only the namespace is changed to match the other PSRs). -It has been thoroughly discussed on `container-interop` [[4]](#link_naming_discussion) and was decided by a vote [[5]](#link_naming_vote). - -The list of options considered with their respective votes are: - -- `ContainerInterface`: +8 -- `ProviderInterface`: +2 -- `LocatorInterface`: 0 -- `ReadableContainerInterface`: -5 -- `ServiceLocatorInterface`: -6 -- `ObjectFactory`: -6 -- `ObjectStore`: -8 -- `ConsumerInterface`: -9 - -## 7. Interface methods - -The choice of which methods the interface would contain was made after a statistical analysis of existing containers. [[6]](#link_statistical_analysis). - -The summary of the analysis showed that: - -- all containers offer a method to get an entry by its id -- a large majority name such method `get()` -- for all containers, the `get()` method has 1 mandatory parameter of type string -- some containers have an optional additional argument for `get()`, but it doesn't have the same purpose between containers -- a large majority of the containers offer a method to test if it can return an entry by its id -- a majority name such method `has()` -- for all containers offering `has()`, the method has exactly 1 parameter of type string -- a large majority of the containers throw an exception rather than returning null when an entry is not found in `get()` -- a large majority of the containers don't implement `ArrayAccess` - -The question of whether to include methods to define entries has been discussed at the very start of the container-interop project [[4]](#link_naming_discussion). -It has been judged that such methods do not belong in the interface described here because it is out of its scope -(see the "Goal" section). - -As a result, the `ContainerInterface` contains two methods: - -- `get()`, returning anything, with one mandatory string parameter. Should throw an exception if the entry is not found. -- `has()`, returning a boolean, with one mandatory string parameter. - -### 7.1. Number of parameters in `get()` method - -While `ContainerInterface` only defines one mandatory parameter in `get()`, it is not incompatible with -existing containers that have additional optional parameters. PHP allows an implementation to offer more parameters -as long as they are optional, because the implementation *does* satisfy the interface. - -Difference with container-interop: [The container-interop spec](https://github.com/container-interop/container-interop/blob/master/docs/ContainerInterface.md) stated that: - -> While `ContainerInterface` only defines one mandatory parameter in `get()`, implementations MAY accept additional optional parameters. - -This sentence was removed from PSR-11 because: - -- It is something that stems from OO principles in PHP, so this is not directly related to PSR-11 -- We do not want to encourage implementors to add additional parameters as we recommend coding against the interface and not the implementation - -However, some implementations have extra optional parameters; that's technically legal. Such implementations are compatible with PSR-11. [[11]](#link_get_optional_parameters) - -### 7.2. Type of the `$id` parameter - -The type of the `$id` parameter in `get()` and `has()` has been discussed in the container-interop project. - -While `string` is used in all the containers that were analyzed, it was suggested that allowing -anything (such as objects) could allow containers to offer a more advanced query API. - -An example given was to use the container as an object builder. The `$id` parameter would then be an -object that would describe how to create an instance. - -The conclusion of the discussion [[7]](#link_method_and_parameters_details) was that this was beyond the scope of getting entries from a container without -knowing how the container provided them, and it was more fit for a factory. - -### 7.3. Exceptions thrown - -This PSR provides 2 interfaces meant to be implemented by container exceptions. - -#### 7.3.1 Base exception - -The `Psr\Container\ContainerExceptionInterface` is the base interface. It SHOULD be implemented by custom exceptions thrown directly by the container. - -It is expected that any exception that is part of the domain of the container implements the `ContainerExceptionInterface`. A few examples: - -- if a container relies on a configuration file and if that configuration file is flawed, the container might throw an `InvalidFileException` implementing the `ContainerExceptionInterface`. -- if a cyclic dependency is detected between dependencies, the container might throw an `CyclicDependencyException` implementing the `ContainerExceptionInterface`. - -However, if the exception is thrown by some code out of the container's scope (for instance an exception thrown while instantiating an entry), the container is not required to wrap this exception in a custom exception implementing the `ContainerExceptionInterface`. - -The usefulness of the base exception interface was questioned: it is not an exception one would typically catch [[8]](#link_base_exception_usefulness). - -However, most PHP-FIG members considered it to be a best practice. Base exception interface are implemented in previous PSRs and several member projects. The base exception interface was therefore kept. - -#### 7.3.2 Not found exception - -A call to the `get` method with a non-existing id must throw an exception implementing the `Psr\Container\NotFoundExceptionInterface`. - -For a given identifier: - -- if the `has` method returns `false`, then the `get` method MUST throw a `Psr\Container\NotFoundExceptionInterface`. -- if the `has` method returns `true`, this does not mean that the `get` method will succeed and throw no exception. It can even throw a `Psr\Container\NotFoundExceptionInterface` if one of the dependencies of the requested entry is missing. - -Therefore, when a user catches the `Psr\Container\NotFoundExceptionInterface`, it has 2 possible meanings [[9]](#link_not_found_behaviour): - -- the requested entry does not exist (bad request) -- or a dependency of the requested entry does not exist (i.e. the container is misconfigured) - -The user can however easily make a distinction with a call to `has`. - -In pseudo-code: - -```php -if (!$container->has($id)) { - // The requested instance does not exist - return; -} -try { - $entry = $container->get($id); -} catch (NotFoundExceptionInterface $e) { - // Since the requested entry DOES exist, a NotFoundExceptionInterface means that the container is misconfigured and a dependency is missing. -} -``` - -8. Implementations ------------------- - -At the time of writing, the following projects already implement and/or consume the `container-interop` version of the interface. - -### Implementors -- [Acclimate](https://github.com/jeremeamia/acclimate-container) -- [Aura.DI](https://github.com/auraphp/Aura.Di) -- [dcp-di](https://github.com/estelsmith/dcp-di) -- [League Container](https://github.com/thephpleague/container) -- [Mouf](http://mouf-php.com) -- [Njasm Container](https://github.com/njasm/container) -- [PHP-DI](http://php-di.org) -- [PimpleInterop](https://github.com/moufmouf/pimple-interop) -- [XStatic](https://github.com/jeremeamia/xstatic) -- [Zend ServiceManager](https://github.com/zendframework/zend-servicemanager) - -### Middleware -- [Alias-Container](https://github.com/thecodingmachine/alias-container) -- [Prefixer-Container](https://github.com/thecodingmachine/prefixer-container) - -### Consumers -- [Behat](https://github.com/Behat/Behat) -- [interop.silex.di](https://github.com/thecodingmachine/interop.silex.di) -- [mindplay/middleman](https://github.com/mindplay-dk/middleman) -- [PHP-DI Invoker](https://github.com/PHP-DI/Invoker) -- [Prophiler](https://github.com/fabfuel/prophiler) -- [Silly](https://github.com/mnapoli/silly) -- [Slim](https://github.com/slimphp/Slim) -- [Splash](http://mouf-php.com/packages/mouf/mvc.splash-common/version/8.0-dev/README.md) -- [Zend Expressive](https://github.com/zendframework/zend-expressive) - -This list is not comprehensive and should be only taken as an example showing that there is considerable interest in the PSR. - -9. People ---------- -### 9.1 Editors - -* [Matthieu Napoli](https://github.com/mnapoli) -* [David Négrier](https://github.com/moufmouf) - -### 9.2 Sponsors - -* [Matthew Weier O'Phinney](https://github.com/weierophinney) (Coordinator) -* [Korvin Szanto](https://github.com/KorvinSzanto) - -### 9.3 Contributors - -Are listed here all people that contributed in the discussions or votes (on container-interop and during migration to PSR-11), by alphabetical order: - -* [Alexandru Pătrănescu](https://github.com/drealecs) -* [Amy Stephen](https://github.com/AmyStephen) -* [Ben Peachey](https://github.com/potherca) -* [David Négrier](https://github.com/moufmouf) -* [Don Gilbert](https://github.com/dongilbert) -* [Jason Judge](https://github.com/judgej) -* [Jeremy Lindblom](https://github.com/jeremeamia) -* [Larry Garfield](https://github.com/crell) -* [Marco Pivetta](https://github.com/Ocramius) -* [Matthieu Napoli](https://github.com/mnapoli) -* [Nelson J Morais](https://github.com/njasm) -* [Paul M. Jones](https://github.com/pmjones) -* [Phil Sturgeon](https://github.com/philsturgeon) -* [Stephan Hochdörfer](https://github.com/shochdoerfer) -* [Taylor Otwell](https://github.com/taylorotwell) - -## 10. Relevant links - -1. [Discussion about the container PSR and the service locator](https://groups.google.com/forum/#!topic/php-fig/pyTXRvLGpsw) -1. [Container-interop's `ContainerInterface.php`](https://github.com/container-interop/container-interop/blob/master/src/Interop/Container/ContainerInterface.php) -1. [List of all issues](https://github.com/container-interop/container-interop/issues?labels=ContainerInterface&milestone=&page=1&state=closed) -1. [Discussion about the interface name and container-interop scope](https://github.com/container-interop/container-interop/issues/1) -1. [Vote for the interface name](https://github.com/container-interop/container-interop/wiki/%231-interface-name:-Vote) -1. [Statistical analysis of existing containers method names](https://gist.github.com/mnapoli/6159681) -1. [Discussion about the method names and parameters](https://github.com/container-interop/container-interop/issues/6) -1. [Discussion about the usefulness of the base exception](https://groups.google.com/forum/#!topic/php-fig/_vdn5nLuPBI) -1. [Discussion about the `NotFoundExceptionInterface`](https://groups.google.com/forum/#!topic/php-fig/I1a2Xzv9wN8) -1. Discussion about get optional parameters [in container-interop](https://github.com/container-interop/container-interop/issues/6) and on the [PHP-FIG mailing list](https://groups.google.com/forum/#!topic/php-fig/zY6FAG4-oz8) diff --git a/_docs/psr/PSR-13-links-meta.md b/_docs/psr/PSR-13-links-meta.md new file mode 100644 index 0000000..d096d28 --- /dev/null +++ b/_docs/psr/PSR-13-links-meta.md @@ -0,0 +1,83 @@ +# Link Definition Meta Document + +## 1. Summary + +Hypermedia links are becoming an increasingly important part of the web, in both HTML contexts +and various API format contexts. However, there is no single common hypermedia format, nor +is there a common way to represent Links between formats. + +This specification aims to provide PHP developers with a simple, common way of representing a +hypermedia link independently of the serialization format that is used. That in turn allows +a system to serialize a response with hypermedia links into one or more wire formats independently +of the process of deciding what those links should be. + +## 2. Scope + +### 2.1 Goals + +* This specification aims to extract and standardize hypermedia link representation between different +formats. + +### 2.2 Non-Goals + +* This specification does not seek to standardize or favor any particular hypermedia serialization format. + +## 3. Design Decisions + +### Why no mutator methods? + +One of the key targets for this specification is PSR-7 Response objects. Response objects by design must be +immutable. Other value-object implementations likely would also require an immutable interface. + +Additionally, some Link Provider objects may not be value objects but other objects within a given +domain, which are able to generate Links on the fly, perhaps off of a database result or other underlying +representation. In those cases a writeable provider definition would be incompatible. + +Therefore, this specification splits accessor methods and evolvable methods into separate interfaces, +allowing objects to implement just the read-only or evolvable versions as appropriate to their use case. + +### Why is rel on a Link object multi-value? + +Different hypermedia standards handle multiple links with the same relationship differently. Some have a single +link that has multiple rel's defined. Others have a single rel entry that then contains multiple links. + +Defining each Link uniquely but allowing it to have multiple rels provides a most-compatible-denominator definition. +A single LinkInterface object may be serialized to one or more link entries in a given hypermedia format, as +appropriate. However, specifying multiple link objects each with a single rel yet the same URI is also legal, and +a hypermedia format can serialize that as appropriate, too. + +### Why is a LinkProviderInterface needed? + +In many contexts, a set of links will be attached to some other object. Those objects may be used in situations +where all that is relevant is their links, or some subset of their links. For example, various different value +objects may be defined that represent different REST formats such as HAL, JSON-LD, or Atom. It may be useful +to extract those links from such an object uniformly for further processing. For instance, next/previous links +may be extracted from an object and added to a PSR-7 Response object as Link headers. Alternatively, many links +would make sense to represent with a "preload" link relationship, which would indicate to an HTTP 2-compatible +web server that the linked resources should be streamed to a client in anticipation of a subsequent request. + +All of those cases are independent of the payload or encoding of the object. By providing a common interface +to access such links, we enable generic handling of the links themselves regardless of the value object or +domain object that is producing them. + +## 4. People + +### 4.1 Editor(s) + +* Larry Garfield + +### 4.2 Sponsors + +* Matthew Weier O'Phinney (coordinator) +* Marc Alexander + +### 4.3 Contributors + +* Evert Pot + +## 5. Votes + +## 6. Relevant links + +* [What's in a link?](http://evertpot.com/whats-in-a-link/) by Evert Pot +* [FIG Link Working Group List](https://groups.google.com/forum/#!forum/php-fig-link) diff --git a/_docs/psr/PSR-13-links.md b/_docs/psr/PSR-13-links.md new file mode 100644 index 0000000..2cec7ff --- /dev/null +++ b/_docs/psr/PSR-13-links.md @@ -0,0 +1,344 @@ +# Link definition interfaces + +Hypermedia links are becoming an increasingly important part of the web, in both HTML contexts +and various API format contexts. However, there is no single common hypermedia format, nor +is there a common way to represent links between formats. + +This specification aims to provide PHP developers with a simple, common way of representing a +hypermedia link independently of the serialization format that is used. That in turn allows +a system to serialize a response with hypermedia links into one or more wire formats independently +of the process of deciding what those links should be. + +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 [RFC 2119](http://tools.ietf.org/html/rfc2119). + +### References + +- [RFC 2119](http://tools.ietf.org/html/rfc2119) +- [RFC 4287](https://tools.ietf.org/html/rfc4287) +- [RFC 5988](https://tools.ietf.org/html/rfc5988) +- [RFC 6570](https://tools.ietf.org/html/rfc6570) +- [IANA Link Relations Registry](http://www.iana.org/assignments/link-relations/link-relations.xhtml) +- [Microformats Relations List](http://microformats.org/wiki/existing-rel-values#HTML5_link_type_extensions) + +## 1. Specification + +### 1.1 Basic links + +A Hypermedia Link consists of, at minimum: +- A URI representing the target resource being referenced. +- A relationship defining how the target resource relates to the source. + +Various other attributes of the Link may exist, depending on the format used. As additional attributes +are not well-standardized or universal, this specification does not seek to standardize them. + +For the purposes of this specification, the following definitions apply. + +* **Implementing Object** - An object that implements one of the interfaces defined by this +specification. + +* **Serializer** - A library or other system that takes one or more Link objects and produces +a serialized representation of it in some defined format. + +### 1.2 Attributes + +All links MAY include zero or more additional attributes beyond the URI and relationship. +There is no formal registry of the values that are allowed here, and validity of values +is dependent on context and often on a particular serialization format. Commonly supported +values include 'hreflang', 'title', and 'type'. + +Serializers MAY omit attributes on a link object if required to do so by the serialization +format. However, serializers SHOULD encode all provided attributes possible in order to +allow for user-extension unless prevented by a serialization format's definition. + +Some attributes (commonly `hreflang`) may appear more than once in their context. Therefore, +an attribute value MAY be an array of values rather than a simple value. Serializers MAY +encode that array in whatever format is appropriate for the serialized format (such +as a space-separated list, comma-separated list, etc.). If a given attribute is not +allowed to have multiple values in a particular context, serializers MUST use the first +value provided and ignore all subsequent values. + +If an attribute value is boolean `true`, serializers MAY use abbreviated forms if appropriate +and supported by a serialization format. For example, HTML permits attributes to +have no value when the attribute's presence has a boolean meaning. This rule applies +if and only if the attribute is boolean `true`, not for any other "truthy" value +in PHP such as integer 1. + +If an attribute value is boolean `false`, serializers SHOULD omit the attribute entirely +unless doing so changes the semantic meaning of the result. This rule applies if +and only if the attribute is boolean `false`, not for any other "falsey" value in PHP +such as integer 0. + +### 1.3 Relationships + +Link relationships are defined as strings, and are either a simple keyword in +case of a publicly defined relationship or an absolute URI in the case of a +private relationships. + +In case a simple keyword is used, it SHOULD match one from the IANA registry at: + +http://www.iana.org/assignments/link-relations/link-relations.xhtml + +Optionally the microformats.org registry MAY be used, but this may not be valid +in every context: + +http://microformats.org/wiki/existing-rel-values + +A relationship that is not defined in one of the above registries or a similar +public registry is considered "private", that is, specific to a particular +application or use case. Such relationships MUST use an absolute URI. + +## 1.4 Link Templates + +[RFC 6570](https://tools.ietf.org/html/rfc6570) defines a format for URI templates, that is, +a pattern for a URI that is expected to be filled in with values provided by a client +tool. Some hypermedia formats support templated links while others do not, and may +have a special way to denote that a link is a template. A Serializer for a format +that does not support URI Templates MUST ignore any templated Links it encounters. + +## 1.5 Evolvable providers + +In some cases, a Link Provider may need the ability to have additional links +added to it. In others, a link provider is necessarily read-only, with links +derived at runtime from some other data source. For that reason, modifiable providers +are a secondary interface that may optionally be implemented. + +Additionally, some Link Provider objects, such as PSR-7 Response objects, are +by design immutable. That means methods to add links to them in-place would be +incompatible. Therefore, the `EvolvableLinkProviderInterface`'s single method +requires that a new object be returned, identical to the original but with +an additional Link object included. + +## 1.6 Evolvable link objects + +Link objects are in most cases value objects. As such, allowing them to evolve +in the same fashion as PSR-7 value objects is a useful option. For that reason, +an additional EvolvableLinkInterface is included that provides methods to +produce new object instances with a single change. The same model is used by PSR-7 +and, thanks to PHP's copy-on-write behavior, is still CPU and memory efficient. + +There is no evolvable method for templated values, however, as the templated value of a +link is based exclusively on the href value. It MUST NOT be set independently, but +derived from whether or not the href value is an RFC 6570 link template. + +## 2. Package + +The interfaces and classes described are provided as part of the +[psr/link](https://packagist.org/packages/psr/link) package. + +## 3. Interfaces + +### 3.1 `Psr\Link\LinkInterface` + +~~~php +withPropagationStopped(); +} +``` + +The latter case, Dispatcher implementations, would require checks on the return value: + +```php +foreach ($provider->getListenersForEvent($event) as $listener) { + $returnedEvent = $listener($event); + + if (! $returnedEvent instanceof $event) { + // This is an exceptional case! + // + // We now have an event of a different type, or perhaps nothing was + // returned by the listener. An event of a different type might mean: + // + // - we need to trigger the new event + // - we have an event mismatch, and should raise an exception + // - we should attempt to trigger the remaining listeners anyway + // + // In the case of nothing being returned, this could mean any of: + // + // - we should continue triggering, using the original event + // - we should stop triggering, and treat this as a request to + // stop propagation + // - we should raise an exception, because the listener did not + // return what was expected + // + // In short, this becomes very hard to specify, or enforce. + } + + if ($returnedEvent instanceof StoppableEventInterface + && $returnedEvent->isPropagationStopped() + ) { + break; + } +} +``` + +In both situations, we would be introducing more potential edge cases, with little benefit, and few language-level mechanisms to guide developers to correct implementation. + +Given these options, the Working Group felt mutable Events were the safer alternative. + +That said, *there is no requirement that an Event be mutable*. Implementers should provide mutator methods on an Event object *if and only if it is necessary* and appropriate to the use case at hand. + +### 4.4 Listener registration + +Experimentation during development of the specification determined that there were a wide range of viable, legitimate means by which a Dispatcher could be informed of a Listener. A Listener: + +* could be registered explicitly; +* could be registered explicitly based on reflection of its signature; +* could be registered with a numeric priority order; +* could be registered using a before/after mechanism to control ordering more precisely; +* could be registered from a service container; +* could use a pre-compile step to generate code; +* could be based on method names on objects in the Event itself; +* could be limited to certain situations or contexts based on arbitrarily complex logic (only for certain users, only on certain days, only if certain system settings are present, etc). + +These and other mechanisms all exist in the wild today in PHP, all are valid use cases worth supporting, and few if any can be conveniently represented as a special case of another. That is, standardizing one way, or even a small set of ways, to inform the system of a Listener turned out to be impractical if not impossible without cutting off many use cases that should be supported. + +The Working Group therefore chose to encapsulate the registration of Listeners behind the `ListenerProviderInterface`. A Provider object may have an explicit registration mechanism available, or multiple such mechanisms, or none. It could also be generated code produced by some compile step. However, that also splits the responsibility of managing the process of dispatching an Event from the process of mapping an Event to Listeners. That way different implementations may be mixed-and-matched with different Provider mechanisms as needed. + +It is even possible, and potentially advisable, to allow libraries to include their own Providers that get aggregated into a common Provider that aggregates their Listeners to return to the Dispatcher. That is one possible way to handle arbitrary Listener registration within an arbitrary framework, although the Working Group is clear that is not the only option. + +While combining the Dispatcher and Provider into a single object is a valid and permissible degenerate case, it is NOT RECOMMENDED as it reduces the flexibility of system integrators. Instead, the Provider SHOULD be composed as a dependent object. + +### 4.5 Deferred listeners + +The specification requires that the callables returned by a Provider MUST all be invoked (unless propagation is explicitly stopped) before the Dispatcher returns. However, the specification also explicitly states that Listeners may enqueue Events for later processing rather than taking immediate action. It is also entirely permissible for a Provider to accept registration of a callable, but then wrap it in another callable before returning it to the Dispatcher. (In that case, the wrapper is the Listener from the Dispatcher's point of view.) That allows all of the following behaviors to be legal: + +* Providers return callable Listeners that were provided to them. +* Providers return callables that create an entry in a queue that will react to the Event with another callable at some later point in time. +* Listeners may themselves create an entry in a queue that will react to the Event at some later point in time. +* Listeners or Providers may trigger an asynchronous task, if running in an environment with support for asynchronous behavior (assuming that the result of the asynchronous task is not needed by the Emitter.) +* Providers may perform such delay or wrapping on Listeners selectively based on arbitrary logic. + +The net result is that Providers and Listeners are responsible for determining when it is safe to defer a response to an Event until some later time. In that case, the Provider or Listener is explicitly opting out of being able to pass meaningful data back to the Emitter, but the Working Group determined that they were in the best position to know if it was safe to do so. + +While technically a side effect of the design, it is essentially the same approach used by Laravel (as of Laravel 5) and has been proven in the wild. + +### 4.6 Return values + +Per the spec, a Dispatcher MUST return the Event passed by the Emitter. This is specified to provide a more ergonomic experience for users, allowing short-hands similar to the following: + +```php +$event = $dispatcher->dispatch(new SomeEvent('some context')); + +$items = $dispatcher->dispatch(new ItemCollector())->getItems(); +``` + +The `EventDispatcher::dispatch()` interface, however, has no return type specified. That is primarily for backward compatibility with existing implementations to make it easier for them to adopt the new interface. Additionally, as Events can be any arbitrary object the return type could only have been `object`, which would provide only minimal (albeit non-zero) value, as that type declaration would not provide IDEs with any useful information nor would it effectively enforce that the same Event is returned. The method return was thus left syntactically untyped. However, returning the same Event object from `dispatch()` is still a requirement and failure to do so is a violation of the specification. + +## 5. People + +The Event Manager Working Group consisted of: + +### 5.1 Editor + +* Larry Garfield + +### 5.2 Sponsor + +* Cees-Jan Kiewiet + +### 5.3 Working Group Members + +* Benjamin Mack +* Elizabeth Smith +* Ryan Weaver +* Matthew Weier O'Phinney + +## 6. Votes + +* [Entrance vote](https://groups.google.com/d/topic/php-fig/6kQFX-lhuk4/discussion) +* [Review Period Initiation](https://groups.google.com/d/topic/php-fig/sR4oEQC3Gz8/discussion) +* [Acceptance](https://groups.google.com/d/topic/php-fig/o4ZSu7vJi2w/discussion) + +## 7. Relevant Links + +* [Inspiration Mailing List Thread][] +* [Entrance vote][] +* [Informal poll on package structure][] +* [Informal poll on naming structure][] + +[Inspiration Mailing List Thread]: https://groups.google.com/forum/#!topic/php-fig/-EJOStgxAwY +[Entrance vote]: https://groups.google.com/d/topic/php-fig/6kQFX-lhuk4/discussion +[Informal poll on package structure]: https://docs.google.com/forms/d/1fvhYUH6xvPgJ1UW9I-3pMGPUtxkt5_Ph6_x_3qXHIuM/edit#responses +[Informal poll on naming structure]: https://docs.google.com/forms/d/1Rs6APuwNx4k2VzJbTgieeNvN48kLu7CG8qn6Dd2FhTw/edit#responses diff --git a/_docs/psr/PSR-14-event-dispatcher.md b/_docs/psr/PSR-14-event-dispatcher.md new file mode 100644 index 0000000..d91e081 --- /dev/null +++ b/_docs/psr/PSR-14-event-dispatcher.md @@ -0,0 +1,180 @@ +Event Dispatcher +================ + +Event Dispatching is a common and well-tested mechanism to allow developers to inject logic into an application easily and consistently. + +The goal of this PSR is to establish a common mechanism for event-based extension and collaboration so that libraries and components may be reused more freely between various applications and frameworks. + +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 [RFC 2119][]. + +[RFC 2119]: http://tools.ietf.org/html/rfc2119 + +## Goal + +Having common interfaces for dispatching and handling events allows developers to create libraries that can interact with many frameworks and other libraries in a common fashion. + +Some examples: + +* A security framework that will prevent saving/accessing data when a user doesn't have permission. +* A common full page caching system. +* Libraries that extend other libraries, regardless of what framework they are both integrated into. +* A logging package to track all actions taken within the application + +## Definitions + +* **Event** - An Event is a message produced by an *Emitter*. It may be any arbitrary PHP object. +* **Listener** - A Listener is any PHP callable that expects to be passed an Event. Zero or more Listeners may be passed the same Event. A Listener MAY enqueue some other asynchronous behavior if it so chooses. +* **Emitter** - An Emitter is any arbitrary code that wishes to dispatch an Event. This is also known as the "calling code". It is not represented by any particular data structure but refers to the use case. +* **Dispatcher** - A Dispatcher is a service object that is given an Event object by an Emitter. The Dispatcher is responsible for ensuring that the Event is passed to all relevant Listeners, but MUST defer determining the responsible listeners to a Listener Provider. +* **Listener Provider** - A Listener Provider is responsible for determining what Listeners are relevant for a given Event, but MUST NOT call the Listeners itself. A Listener Provider may specify zero or more relevant Listeners. + +## Events + +Events are objects that act as the unit of communication between an Emitter and appropriate Listeners. + +Event objects MAY be mutable should the use case call for Listeners providing information back to the Emitter. However, if no such bidirectional communication is needed then it is RECOMMENDED that the Event be defined as immutable; i.e., defined such that it lacks mutator methods. + +Implementers MUST assume that the same object will be passed to all Listeners. + +It is RECOMMENDED, but NOT REQUIRED, that Event objects support lossless serialization and deserialization; `$event == unserialize(serialize($event))` SHOULD hold true. Objects MAY leverage PHP’s `Serializable` interface, `__sleep()` or `__wakeup()` magic methods, or similar language functionality if appropriate. + +## Stoppable Events + +A **Stoppable Event** is a special case of Event that contains additional ways to prevent further Listeners from being called. It is indicated by implementing the `StoppableEventInterface`. + +An Event that implements `StoppableEventInterface` MUST return `true` from `isPropagationStopped()` when whatever Event it represents has been completed. It is up to the implementer of the class to determine when that is. For example, an Event that is asking for a PSR-7 `RequestInterface` object to be matched with a corresponding `ResponseInterface` object could have a `setResponse(ResponseInterface $res)` method for a Listener to call, which causes `isPropagationStopped()` to return `true`. + +## Listeners + +A Listener may be any PHP callable. A Listener MUST have one and only one parameter, which is the Event to which it responds. Listeners SHOULD type hint that parameter as specifically as is relevant for their use case; that is, a Listener MAY type hint against an interface to indicate it is compatible with any Event type that implements that interface, or to a specific implementation of that interface. + +A Listener SHOULD have a `void` return, and SHOULD type hint that return explicitly. A Dispatcher MUST ignore return values from Listeners. + +A Listener MAY delegate actions to other code. That includes a Listener being a thin wrapper around an object that runs the actual business logic. + +A Listener MAY enqueue information from the Event for later processing by a secondary process, using cron, a queue server, or similar techniques. It MAY serialize the Event object itself to do so; however, care should be taken that not all Event objects may be safely serializable. A secondary process MUST assume that any changes it makes to an Event object will NOT propagate to other Listeners. + +## Dispatcher + +A Dispatcher is a service object implementing `EventDispatcherInterface`. It is responsible for retrieving Listeners from a Listener Provider for the Event dispatched, and invoking each Listener with that Event. + +A Dispatcher: + +* MUST call Listeners synchronously in the order they are returned from a ListenerProvider. +* MUST return the same Event object it was passed after it is done invoking Listeners. +* MUST NOT return to the Emitter until all Listeners have executed. + +If passed a Stoppable Event, a Dispatcher + +* MUST call `isPropagationStopped()` on the Event before each Listener has been called. If that method returns `true` it MUST return the Event to the Emitter immediately and MUST NOT call any further Listeners. This implies that if an Event is passed to the Dispatcher that always returns `true` from `isPropagationStopped()`, zero listeners will be called. + +A Dispatcher SHOULD assume that any Listener returned to it from a Listener Provider is type-safe. That is, the Dispatcher SHOULD assume that calling `$listener($event)` will not produce a `TypeError`. + +[Promise object]: https://promisesaplus.com/ + +### Error handling + +An Exception or Error thrown by a Listener MUST block the execution of any further Listeners. An Exception or Error thrown by a Listener MUST be allowed to propagate back up to the Emitter. + +A Dispatcher MAY catch a thrown object to log it, allow additional action to be taken, etc., but then MUST rethrow the original throwable. + +## Listener Provider + +A Listener Provider is a service object responsible for determining what Listeners are relevant to and should be called for a given Event. It may determine both what Listeners are relevant and the order in which to return them by whatever means it chooses. That MAY include: + +* Allowing for some form of registration mechanism so that implementers may assign a Listener to an Event in a fixed order. +* Deriving a list of applicable Listeners through reflection based on the type and implemented interfaces of the Event. +* Generating a compiled list of Listeners ahead of time that may be consulted at runtime. +* Implementing some form of access control so that certain Listeners will only be called if the current user has a certain permission. +* Extracting some information from an object referenced by the Event, such as an Entity, and calling pre-defined lifecycle methods on that object. +* Delegating its responsibility to one or more other Listener Providers using some arbitrary logic. + +Any combination of the above, or other mechanisms, MAY be used as desired. + +Listener Providers SHOULD use the class name of an Event to differentiate one event from another. They MAY also consider any other information on the event as appropriate. + +Listener Providers MUST treat parent types identically to the Event's own type when determining listener applicability. In the following case: + +```php +class A {} + +class B extends A {} + +$b = new B(); + +function listener(A $event): void {}; +``` + +A Listener Provider MUST treat `listener()` as an applicable listener for `$b`, as it is type compatible, unless some other criteria prevents it from doing so. + +## Object composition + +A Dispatcher SHOULD compose a Listener Provider to determine relevant listeners. It is RECOMMENDED that a Listener Provider be implemented as a distinct object from the Dispatcher but that is NOT REQUIRED. + +## Interfaces + +```php +namespace Psr\EventDispatcher; + +/** + * Defines a dispatcher for events. + */ +interface EventDispatcherInterface +{ + /** + * Provide all relevant listeners with an event to process. + * + * @param object $event + * The object to process. + * + * @return object + * The Event that was passed, now modified by listeners. + */ + public function dispatch(object $event); +} +``` + +```php +namespace Psr\EventDispatcher; + +/** + * Mapper from an event to the listeners that are applicable to that event. + */ +interface ListenerProviderInterface +{ + /** + * @param object $event + * An event for which to return the relevant listeners. + * @return iterable[callable] + * An iterable (array, iterator, or generator) of callables. Each + * callable MUST be type-compatible with $event. + */ + public function getListenersForEvent(object $event) : iterable; +} +``` + +```php +namespace Psr\EventDispatcher; + +/** + * An Event whose processing may be interrupted when the event has been handled. + * + * A Dispatcher implementation MUST check to determine if an Event + * is marked as stopped after each listener is called. If it is then it should + * return immediately without calling any further Listeners. + */ +interface StoppableEventInterface +{ + /** + * Is propagation stopped? + * + * This will typically only be used by the Dispatcher to determine if the + * previous listener halted propagation. + * + * @return bool + * True if the Event is complete and no further listeners should be called. + * False to continue calling listeners. + */ + public function isPropagationStopped() : bool; +} +``` diff --git a/_docs/psr/PSR-15-request-handlers-meta.md b/_docs/psr/PSR-15-request-handlers-meta.md new file mode 100644 index 0000000..7ddddc6 --- /dev/null +++ b/_docs/psr/PSR-15-request-handlers-meta.md @@ -0,0 +1,641 @@ +HTTP Server Request Handlers Meta Document +========================================== + +## 1. Summary + +The purpose of this PSR is to define formal interfaces for HTTP server request +handlers ("request handlers") and HTTP server request middleware ("middleware") +that are compatible with HTTP messages as defined in [PSR-7][psr7] or subsequent +replacement PSRs. + +_Note: All references to "request handlers" and "middleware" are specific to +**server request** processing._ + +[psr7]: http://www.php-fig.org/psr/psr-7/ + +## 2. Why Bother? + +The HTTP messages specification does not contain any reference to request +handlers or middleware. + +Request handlers are a fundamental part of any web application. The handler is +the component that receives a request and produces a response. Nearly all code +that works with HTTP messages will have some kind of request handler. + +[Middleware][middleware] has existed for many years in the PHP ecosystem. The +general concept of reusable middleware was popularized by [StackPHP][stackphp]. +Since the release of HTTP messages as a PSR, many frameworks have adopted +middleware that use HTTP message interfaces. + +Agreeing on formal request handler and middleware interfaces eliminates several +problems and has a number of benefits: + +* Provides a formal standard for developers to commit to. +* Enables any middleware component to run in any compatible framework. +* Eliminates duplication of similar interfaces defined by various frameworks. +* Avoids minor discrepancies in method signatures. + +[middleware]: https://en.wikipedia.org/wiki/Middleware +[stackphp]: http://stackphp.com/ + +## 3. Scope + +### 3.1 Goals + +* Create a request handler interface that uses HTTP messages. +* Create a middleware interface that uses HTTP messages. +* Implement request handler and middleware signatures that are based on + best practices. +* Ensure that request handlers and middleware will be compatible with any + implementation of HTTP messages. + +### 3.2 Non-Goals + +* Attempting to define the mechanism by which HTTP responses are created. +* Attempting to define interfaces for client/asynchronous middleware. +* Attempting to define how middleware is dispatched. + +## 4. Request Handler Approaches + +There are many approaches to request handlers that use HTTP messages. However, +the general process is the same in all of them: + +Given an HTTP request, produce an HTTP response for that request. + +The internal requirements of that process will vary from framework to framework +and application to application. This proposal makes no effort to determine what +that process should be. + +## 5. Middleware Approaches + +There are currently two common approaches to middleware that use HTTP messages. + +### 5.1 Double Pass + +The signature used by most middleware implementations has been mostly the same +and is based on [Express middleware][express], which is defined as: + +``` +fn(request, response, next): response +``` + +[express]: http://expressjs.com/en/guide/writing-middleware.html + +Based on the middleware implementations already used by frameworks that have +adopted this signature, the following commonalities are observed: + +* The middleware is defined as a [callable][php-callable]. +* The middleware is passed 3 arguments during invocation: + 1. A `ServerRequestInterface` implementation. + 2. A `ResponseInterface` implementation. + 3. A `callable` that receives the request and response to delegate to the next middleware. + +[php-callable]: http://php.net/manual/language.types.callable.php + +A significant number of projects provide and/or use exactly the same interface. +This approach is often referred to as "double pass" in reference to both the +request and response being passed to the middleware. + +#### 5.1.1 Projects Using Double Pass + +* [mindplay/middleman v1](https://github.com/mindplay-dk/middleman/blob/1.0.0/src/MiddlewareInterface.php#L24) +* [relay/relay v1](https://github.com/relayphp/Relay.Relay/blob/1.0.0/src/MiddlewareInterface.php#L24) +* [slim/slim v3](https://github.com/slimphp/Slim/blob/3.4.0/Slim/MiddlewareAwareTrait.php#L66-L75) +* [zendframework/zend-stratigility v1](https://github.com/zendframework/zend-stratigility/blob/1.0.0/src/MiddlewarePipe.php#L69-L79) + +#### 5.1.2 Middleware Implementing Double Pass + +* [bitexpert/adroit](https://github.com/bitExpert/adroit) +* [akrabat/rka-ip-address-middleware](https://github.com/akrabat/rka-ip-address-middleware) +* [akrabat/rka-scheme-and-host-detection-middleware](https://github.com/akrabat/rka-scheme-and-host-detection-middleware) +* [bear/middleware](https://github.com/bearsunday/BEAR.Middleware) +* [los/api-problem](https://github.com/Lansoweb/api-problem) +* [los/los-rate-limit](https://github.com/Lansoweb/LosRateLimit) +* [monii/monii-action-handler-psr7-middleware](https://github.com/monii/monii-action-handler-psr7-middleware) +* [monii/monii-nikic-fast-route-psr7-middleware](https://github.com/monii/monii-nikic-fast-route-psr7-middleware) +* [monii/monii-response-assertion-psr7-middleware](https://github.com/monii/monii-response-assertion-psr7-middleware) +* [mtymek/blast-base-url](https://github.com/mtymek/blast-base-url) +* [ocramius/psr7-session](https://github.com/Ocramius/PSR7Session) +* [oscarotero/psr7-middlewares](https://github.com/oscarotero/psr7-middlewares) +* [php-middleware/block-robots](https://github.com/php-middleware/block-robots) +* [php-middleware/http-authentication](https://github.com/php-middleware/http-authentication) +* [php-middleware/log-http-messages](https://github.com/php-middleware/log-http-messages) +* [php-middleware/maintenance](https://github.com/php-middleware/maintenance) +* [php-middleware/phpdebugbar](https://github.com/php-middleware/phpdebugbar) +* [php-middleware/request-id](https://github.com/php-middleware/request-id) +* [relay/middleware](https://github.com/relayphp/Relay.Middleware) + +The primary downside of this interface is that the while the interface itself is +a callable, there is currently no way to strictly type a closure. + +### 5.2 Single Pass (Lambda) + +The other approach to middleware is much closer to [StackPHP][stackphp] style +and is defined as: + +``` +fn(request, next): response +``` + +Middleware taking this approach generally has the following commonalities: + +* The middleware is defined with a specific interface with a method that takes + the request for processing. +* The middleware is passed 2 arguments during invocation: + 1. An HTTP request message. + 2. A request handler to which the middleware can delegate the responsibility + of producing an HTTP response message. + +In this form, middleware has no access to a response until one is generated by +the request handler. Middleware can then modify the response before returning it. + +This approach is often referred to as "single pass" or "lambda" in reference to +only the request being passed to the middleware. + +#### 5.2.1 Projects Using Single Pass + +There are fewer examples of this approach within projects using HTTP messages, +with one notable exception. + +[Guzzle middleware][guzzle-middleware] is focused on outgoing (client) requests +and uses this signature: + +```php +function (RequestInterface $request, array $options): ResponseInterface +``` + +#### 5.2.2 Additional Projects Using Single Pass + +There are also significant projects that predate HTTP messages using this approach. + +[StackPHP][stackphp] is based on [Symfony HttpKernel][httpkernel] and supports +middleware with this signature: + +```php +function handle(Request $request, $type, $catch): Response +``` + +_Note: While Stack has multiple arguments, a response object is not included._ + +[Laravel middleware][laravel-middleware] uses Symfony components and supports +middleware with this signature: + +```php +function handle(Request $request, callable $next): Response +``` + +[guzzle-middleware]: http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html +[httpkernel]: https://symfony.com/doc/2.0/components/http_kernel/introduction.html +[laravel-middleware]: https://laravel.com/docs/master/middleware + +### 5.3 Comparison of Approaches + +The single pass approach to middleware has been well established in the PHP +community for many years. This is most evident with the large number of packages +that are based around StackPHP. + +The double pass approach is much newer but has been almost universally used by +early adopters of HTTP messages (PSR-7). + +### 5.4 Chosen Approach + +Despite the nearly universal adoption of the double-pass approach, there are +significant issues regarding implementation. + +The most severe is that passing an empty response has no guarantees that the +response is in a usable state. This is further exacerbated by the fact that a +middleware may modify the response before passing it for further processing. + +Further compounding the problem is that there is no way to ensure that the +response body has not been written to, which can lead to incomplete output or +error responses being sent with cache headers attached. It is also possible +to end up with [corrupted body content][rob-allen-filtering] when writing over +existing body content if the new content is shorter than the original. The most +effective way to resolve these issues is to always provide a fresh stream when +modifying the body of a message. + +[rob-allen-filtering]: https://akrabat.com/filtering-the-psr-7-body-in-middleware/ + +Some have argued that passing the response helps ensure dependency inversion. +While it is true that it helps avoid depending on a specific implementation of +HTTP messages, the problem can also be resolved by injecting factories into the +middleware to create HTTP message objects, or by injecting empty message instances. +With the creation of HTTP Factories in [PSR-17][psr17], a standard approach to +handling dependency inversion is possible. + +[psr17]: https://github.com/php-fig/fig-standards/blob/master/proposed/http-factory/http-factory-meta.md + +A more subjective, but also important, concern is that existing double-pass +middleware typically uses the `callable` type hint to refer to middleware. +This makes strict typing impossible, as there is no assurance that the `callable` +being passed implements a middleware signature, which reduces runtime safety. + +**Due to these significant issues, the lambda approach has been chosen for this proposal.** + +## 6. Design Decisions + +### 6.1 Request Handler Design + +The `RequestHandlerInterface` defines a single method that accepts a request and +MUST return a response. The request handler MAY delegate to another handler. + +#### Why is a server request required? + +To make it clear that the request handler can only be used in a server side context. +In an client side context, a [promise][promises] would likely be returned instead +of a response. + +[promises]: https://promisesaplus.com/ + +#### Why the term "handler"? + +The term "handler" means something designated to manage or control. In terms of +request processing, a request handler is the point where the request must be +acted upon to create a response. + +As opposed to the term "delegate", which was used in a previous version of this +specification, the internal behavior of this interface is not specified. +As long as the request handler ultimately produces a response, it is valid. + +#### Why doesn't request handler use `__invoke`? + +Using `__invoke` is less transparent than using a named method. It also makes +it easier to call the request handler when it is assigned to a class variable, +without using `call_user_func` or other less common syntax. + +_See [PHP-FIG discussion of FrameInterface][] for + additional information._ + +### 6.2 Middleware Design + +The `MiddlewareInterface` defines a single method that accepts an HTTP request +and a request handler and must return a response. The middleware may: + +- Evolve the request before passing it to the request handler. +- Evolve the response received from the request handler before returning it. +- Create and return a response without passing the request to the request handler, + thereby handling the request itself. + +When delegating from one middleware to another in a sequence, one approach for +dispatching systems is to use an intermediary request handler composing the +middleware sequence as a way to link middleware together. The final or innermost +middleware will act as a gateway to application code and generate a response +from its results; alternately, the middleware MAY delegate this responsibility +to a dedicated request handler. + +#### Why doesn't middleware use `__invoke`? + +Doing so would conflict with existing middleware that implements the double-pass +approach and may want to implement the middleware interface for purposes of +forward compatibility with this specification. + +#### Why the name `process()`? + +We reviewed a number of existing monolithic and middleware frameworks to +determine what method(s) each defined for processing incoming requests. We found +the following were commonly used: + +- `__invoke` (within middleware systems, such as Slim, Expressive, Relay, etc.) +- `handle` (in particular, software derived from Symfony's [HttpKernel][HttpKernel]) +- `dispatch` (Zend Framework's [DispatchableInterface][DispatchableInterface]) + +[HttpKernel]: https://symfony.com/doc/current/components/http_kernel.html +[DispatchableInterface]: https://github.com/zendframework/zend-stdlib/blob/980ce463c29c1a66c33e0eb67961bba895d0e19e/src/DispatchableInterface.php + +We chose to allow a forward-compatible approach for such classes to repurpose +themselves as middleware (or middleware compatible with this specification), +and thus needed to choose a name not in common usage. As such, we chose +`process`, to indicate _processing_ a request. + +#### Why is a server request required? + +To make it clear that the middleware can only be used in a synchronous, server +side context. + +While not all middleware will need to use the additional methods defined by the +server request interface, outbound requests are typically processed asynchronously +and would typically return a [promise][promises] of a response. (This is primarily +due to the fact that multiple requests can be made in parallel and processed as +they are returned.) It is outside the scope of this proposal to address the needs +of asynchronous request/response life cycles. + +Attempting to define client middleware would be premature at this point. Any future +proposal that is focused on client side request processing should have the opportunity +to define a standard that is specific to the nature of asynchronous middleware. + +_See [PHP-FIG discussion about client vs server side middleware][] for additional information._ + +#### What is the role of the request handler? + +Middleware has the following roles: + +- Producing a response on its own. If specific request conditions are met, the + middleware can produce and return a response. + +- Returning the result of the request handler. In cases where the middleware + cannot produce its own response, it can delegate to the request handler to + produce one; sometimes this may involve providing a transformed request (e.g., + to inject a request attribute, or the results of parsing the request body). + +- Manipulating and returning the response produced by the request handler. In + some cases, the middleware may be interested in manipulating the response + the request handler returns (e.g., to gzip the response body, to add CORS + headers, etc.). In such cases, the middleware will capture the response + returned by the request handler, and return a transformed response on + completion. + +In these latter two cases, the middleware may have code such as the following: + +```php +// Straight delegation: +return $handler->handle($request); + +// Capturing the response to manipulate: +$response = $handler->handle($request); +``` + +How the handler acts is entirely up to the developer, so long as it produces a +response. + +In one common scenario, the handler implements a _queue_ or a _stack_ of +middleware instances internally. In such cases, calling +`$handler->handle($request)` will advance the internal pointer, pull the +middleware associated with that pointer, and call it using +`$middleware->process($request, $this)`. If no more middleware exists, it will +generally either raise an exception or return a canned response. + +Another possibility is for _routing middleware_ that matches the incoming +server request to a specific handler, and then returns the response generated by +executing that handler. If unable to route to a handler, it would instead +execute the handler provided to the middleware. (This sort of mechanism can even +be used in conjunction with middleware queues and stacks.) + +### 6.3 Example Interface Interactions + +The two interfaces, `RequestHandlerInterface` and `MiddlewareInterface`, were +designed to work in conjunction with one another. Middleware gains flexibility +when de-coupled from any over-arching application layer, and instead only +relying on the provided request handler to produce a response. + +Two approaches to middleware dispatch systems that the Working Group observed +and/or implemented are demonstrated below. Additionally, examples of re-usable +middleware are provided to demonstrate how to write middleware that is +loosely-coupled. + +Please note that these are not suggested as definitive or exclusive approaches +to defining middleware dispatch systems. + +#### Queue-based request handler + +In this approach, a request handler maintains a queue of middleware, and a +fallback response to return if the queue is exhausted without returning a +response. When executing the first middleware, the queue passes itself as a +request handler to the middleware. + +```php +class QueueRequestHandler implements RequestHandlerInterface +{ + private $middleware = []; + private $fallbackHandler; + + public function __construct(RequestHandlerInterface $fallbackHandler) + { + $this->fallbackHandler = $fallbackHandler; + } + + public function add(MiddlewareInterface $middleware) + { + $this->middleware[] = $middleware; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + // Last middleware in the queue has called on the request handler. + if (0 === count($this->middleware)) { + return $this->fallbackHandler->handle($request); + } + + $middleware = array_shift($this->middleware); + return $middleware->process($request, $this); + } +} +``` + +An application bootstrap might then look like this: + +```php +// Fallback handler: +$fallbackHandler = new NotFoundHandler(); + +// Create request handler instance: +$app = new QueueRequestHandler($fallbackHandler); + +// Add one or more middleware: +$app->add(new AuthorizationMiddleware()); +$app->add(new RoutingMiddleware()); + +// execute it: +$response = $app->handle(ServerRequestFactory::fromGlobals()); +``` + +This system has two request handlers: one that will produce a response if the +last middleware delegates to the request handler, and one for dispatching the +middleware layers. (In this example, the `RoutingMiddleware` will likely execute +composed handlers on a successful route match; see more on that below.) + +This approach has the following benefits: + +- Middleware does not need to know anything about any other middleware or how it + is composed in the application. +- The `QueueRequestHandler` is agnostic of the PSR-7 implementation in use. +- Middleware is executed in the order it is added to the application, making the + code explicit. +- Generation of the "fallback" response is delegated to the application + developer. This allows the developer to determine whether that should be a + "404 Not Found" condition, a default page, etc. + +#### Decoration-based request handler + +In this approach, a request handler implementation decorates both a middleware +instance and a fallback request handler to pass to it. The application is built +from the outside-in, passing each request handler "layer" to the next outer one. + +```php +class DecoratingRequestHandler implements RequestHandlerInterface +{ + private $middleware; + private $nextHandler; + + public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $nextHandler) + { + $this->middleware = $middleware; + $this->nextHandler = $nextHandler; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + return $this->middleware->process($request, $this->nextHandler); + } +} + +// Create a response prototype to return if no middleware can produce a response +// on its own. This could be a 404, 500, or default page. +$responsePrototype = (new Response())->withStatus(404); +$innerHandler = new class ($responsePrototype) implements RequestHandlerInterface { + private $responsePrototype; + + public function __construct(ResponseInterface $responsePrototype) + { + $this->responsePrototype = $responsePrototype; + } + + public function handle(ServerRequestInterface $request): ResponseInterface + { + return $this->responsePrototype; + } +}; + +$layer1 = new DecoratingRequestHandler(new RoutingMiddleware(), $innerHandler); +$layer2 = new DecoratingRequestHandler(new AuthorizationMiddleware(), $layer1); + +$response = $layer2->handle(ServerRequestFactory::fromGlobals()); +``` + +Similar to the queue-based middleware, request handlers serve two purposes in +this system: + +- Producing a fallback response if no other layer does. +- Dispatching middleware. + +#### Reusable Middleware Examples + +In the examples above, we have two middleware composed in each. In order for +these to work in either situation, we need to write them such that they interact +appropriately. + +Implementors of middleware striving for maximum interoperability may want to +consider the following guidelines: + +- Test the request for a required condition. If it does not satisfy that + condition, use a composed prototype response or a composed response factory + to generate and return a response. + +- If pre-conditions are met, delegate creation of the response to the provided + request handler, optionally providing a "new" request by manipulating the + provided request (e.g., `$handler->handle($request->withAttribute('foo', + 'bar')`). + +- Either pass the response returned by the request handler unaltered, or provide + a new response by manipulating the one returned (e.g., `return + $response->withHeader('X-Foo-Bar', 'baz')`). + +The `AuthorizationMiddleware` is one that will exercise all three of these guidelines: + +- If authorization is required, but the request is not authorized, it will use a + composed prototype response to produce an "unauthorized" response. +- If authorization is not required, it will delegate the request to the handler + without changes. +- If authorization is required and the request is authorized, it will delegate + the request to the handler, and sign the response returned based on the request. + +```php +class AuthorizationMiddleware implements MiddlewareInterface +{ + private $authorizationMap; + + public function __construct(AuthorizationMap $authorizationMap) + { + $this->authorizationMap = $authorizationMap; + } + + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + if (! $this->authorizationMap->needsAuthorization($request)) { + return $handler->handle($request); + } + + if (! $this->authorizationMap->isAuthorized($request)) { + return $this->authorizationMap->prepareUnauthorizedResponse(); + } + + $response = $handler->handle($request); + return $this->authorizationMap->signResponse($response, $request); + } +} +``` + +Note that the middleware is not concerned with how the request handler is +implemented; it merely uses it to produce a response when pre-conditions have +been met. + +The `RoutingMiddleware` implementation described below follows a similar +process: it analyzes the request to see if it matches known routes. In this +particular implementation, routes map to request handlers, and the middleware +essentially delegates to them in order to produce a response. However, in the +case that no route is matched, it will execute the handler passed to it to +produce the response to return. + +```php +class RoutingMiddleware implements MiddlewareInterface +{ + private $router; + + public function __construct(Router $router) + { + $this->router = $router; + } + + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $result = $this->router->match($request); + + if ($result->isSuccess()) { + return $result->getHandler()->handle($request); + } + + return $handler->handle($request); + } +} +``` + +## 7. People + +This PSR was produced by a FIG Working Group with the following members: + +* Matthew Weier O'Phinney (sponsor), +* Woody Gilk (editor), +* Glenn Eggleton +* Matthieu Napoli +* Oscar Otero +* Korvin Szanto +* Stefano Torresi + +The working group would also like to acknowledge the contributions of: + +* Jason Coward, +* Paul M. Jones, +* Rasmus Schultz, + +## 8. Votes + +* [Working Group Formation](https://groups.google.com/d/msg/php-fig/rPFRTa0NODU/tIU9BZciAgAJ) +* [Review Period Initiation](https://groups.google.com/d/msg/php-fig/mfTrFinTvEM/PiYvU2S6BAAJ) +* [Acceptance](https://groups.google.com/d/msg/php-fig/bhQmHt39hJE/ZCYrK_O2AQAJ) + +## 9. Relevant Links + +_**Note:** Order descending chronologically._ + +* [PHP-FIG mailing list thread][] +* [The PHP League middleware proposal][] +* [PHP-FIG discussion of FrameInterface][] +* [PHP-FIG discussion about client vs server side middleware][] + +## 10. Errata + +... + +[PHP-FIG mailing list thread]: https://groups.google.com/d/msg/php-fig/vTtGxdIuBX8/NXKieN9vDQAJ +[The PHP League middleware proposal]: https://groups.google.com/d/msg/thephpleague/jyztj-Nz_rw/I4lHVFigAAAJ +[PHP-FIG discussion of FrameInterface]: https://groups.google.com/d/msg/php-fig/V12AAcT_SxE/aRXmNnIVCwAJ +[PHP-FIG discussion about client vs server side middleware]: https://groups.google.com/d/topic/php-fig/vBk0BRgDe2s/discussion diff --git a/_docs/psr/PSR-15-request-handlers.md b/_docs/psr/PSR-15-request-handlers.md index 5cef359..67d1a9c 100644 --- a/_docs/psr/PSR-15-request-handlers.md +++ b/_docs/psr/PSR-15-request-handlers.md @@ -1,26 +1,12 @@ ---- -title: PRS-15 -category: PSRs -order: 9 ---- - -| Informações Adicionais | -| -----------------------------------------------------------------------------------------| -| [HTTP Server Request Handlers][HTTP Server Request Handlers] | -| [HTTP Server Request Handlers Meta Document][HTTP Server Request Handlers Meta Document] | - -[HTTP Server Request Handlers]: #HTTP Server Request Handlers -[HTTP Server Request Handlers Meta Document]: #HTTP Server Request Handlers Meta Document - - -

HTTP Server Request Handlers

+HTTP Server Request Handlers +============================ This document describes common interfaces for HTTP server request handlers ("request handlers") and HTTP server middleware components ("middleware") that use HTTP messages as described by [PSR-7][psr7] or subsequent replacement PSRs. -HTTP request handlers are a fundamental part of any web application. Server side +HTTP request handlers are a fundamental part of any web application. Server-side code receives a request message, processes it, and produces a response message. HTTP middleware is a way to move common request and response processing away from the application layer. @@ -79,7 +65,7 @@ specific HTTP message implementation. ### 1.4 Handling Exceptions -It is RECOMMENDED that any application using middleware include a component +It is RECOMMENDED that any application using middleware includes a component that catches exceptions and converts them into responses. This middleware SHOULD be the first component executed and wrap all further processing to ensure that a response is always generated. @@ -97,7 +83,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Handles a server request and produces a response + * Handles a server request and produces a response. * * An HTTP request handler process an HTTP request in order to produce an * HTTP response. @@ -105,7 +91,7 @@ use Psr\Http\Message\ServerRequestInterface; interface RequestHandlerInterface { /** - * Handles a request and produces a response + * Handles a request and produces a response. * * May call other collaborating code to generate the response. */ @@ -124,7 +110,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** - * Participant in processing a server request and response + * Participant in processing a server request and response. * * An HTTP middleware component participates in processing an HTTP message: * by acting on the request, generating the response, or forwarding the @@ -133,7 +119,7 @@ use Psr\Http\Message\ServerRequestInterface; interface MiddlewareInterface { /** - * Process an incoming server request + * Process an incoming server request. * * Processes an incoming server request in order to produce a response. * If unable to produce the response itself, it may delegate to the provided @@ -142,641 +128,3 @@ interface MiddlewareInterface public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface; } ``` - - -

HTTP Server Request Handlers Meta Document

- -## 1. Summary - -The purpose of this PSR is to define formal interfaces for HTTP server request -handlers ("request handlers") and HTTP server request middleware ("middleware") -that are compatible with HTTP messages as defined in [PSR-7][psr7] or subsequent -replacement PSRs. - -_Note: All references to "request handlers" and "middleware" are specific to -**server request** processing._ - -[psr7]: http://www.php-fig.org/psr/psr-7/ - -## 2. Why Bother? - -The HTTP messages specification does not contain any reference to request -handlers or middleware. - -Request handlers are a fundamental part of any web application. The handler is -the component that receives a request and produces a response. Nearly all code -that works with HTTP messages will have some kind of request handler. - -[Middleware][middleware] has existed for many years in the PHP ecosystem. The -general concept of reusable middleware was popularized by [StackPHP][stackphp]. -Since the release of HTTP messages as a PSR, many frameworks have adopted -middleware that use HTTP message interfaces. - -Agreeing on formal request handler and middleware interfaces eliminates several -problems and has a number of benefits: - -* Provides a formal standard for developers to commit to. -* Enables any middleware component to run in any compatible framework. -* Eliminates duplication of similar interfaces defined by various frameworks. -* Avoids minor discrepancies in method signatures. - -[middleware]: https://en.wikipedia.org/wiki/Middleware -[stackphp]: http://stackphp.com/ - -## 3. Scope - -### 3.1 Goals - -* Create a request handler interface that uses HTTP messages. -* Create a middleware interface that uses HTTP messages. -* Implement request handler and middleware signatures that are based on - best practices. -* Ensure that request handlers and middleware will be compatible with any - implementation of HTTP messages. - -### 3.2 Non-Goals - -* Attempting to define the mechanism by which HTTP responses are created. -* Attempting to define interfaces for client/asynchronous middleware. -* Attempting to define how middleware is dispatched. - -## 4. Request Handler Approaches - -There are many approaches to request handlers that use HTTP messages. However, -the general process is the same in all of them: - -Given an HTTP request, produce an HTTP response for that request. - -The internal requirements of that process will vary from framework to framework -and application to application. This proposal makes no effort to determine what -that process should be. - -## 5. Middleware Approaches - -There are currently two common approaches to middleware that use HTTP messages. - -### 5.1 Double Pass - -The signature used by most middleware implementations has been mostly the same -and is based on [Express middleware][express], which is defined as: - -``` -fn(request, response, next): response -``` - -[express]: http://expressjs.com/en/guide/writing-middleware.html - -Based on the middleware implementations already used by frameworks that have -adopted this signature, the following commonalities are observed: - -* The middleware is defined as a [callable][php-callable]. -* The middleware is passed 3 arguments during invocation: - 1. A `ServerRequestInterface` implementation. - 2. A `ResponseInterface` implementation. - 3. A `callable` that receives the request and response to delegate to the next middleware. - -[php-callable]: http://php.net/manual/language.types.callable.php - -A significant number of projects provide and/or use exactly the same interface. -This approach is often referred to as "double pass" in reference to both the -request and response being passed to the middleware. - -#### 5.1.1 Projects Using Double Pass - -* [mindplay/middleman v1](https://github.com/mindplay-dk/middleman/blob/1.0.0/src/MiddlewareInterface.php#L24) -* [relay/relay v1](https://github.com/relayphp/Relay.Relay/blob/1.0.0/src/MiddlewareInterface.php#L24) -* [slim/slim v3](https://github.com/slimphp/Slim/blob/3.4.0/Slim/MiddlewareAwareTrait.php#L66-L75) -* [zendframework/zend-stratigility v1](https://github.com/zendframework/zend-stratigility/blob/1.0.0/src/MiddlewarePipe.php#L69-L79) - -#### 5.1.2 Middleware Implementing Double Pass - -* [bitexpert/adroit](https://github.com/bitExpert/adroit) -* [akrabat/rka-ip-address-middleware](https://github.com/akrabat/rka-ip-address-middleware) -* [akrabat/rka-scheme-and-host-detection-middleware](https://github.com/akrabat/rka-scheme-and-host-detection-middleware) -* [bear/middleware](https://github.com/bearsunday/BEAR.Middleware) -* [los/api-problem](https://github.com/Lansoweb/api-problem) -* [los/los-rate-limit](https://github.com/Lansoweb/LosRateLimit) -* [monii/monii-action-handler-psr7-middleware](https://github.com/monii/monii-action-handler-psr7-middleware) -* [monii/monii-nikic-fast-route-psr7-middleware](https://github.com/monii/monii-nikic-fast-route-psr7-middleware) -* [monii/monii-response-assertion-psr7-middleware](https://github.com/monii/monii-response-assertion-psr7-middleware) -* [mtymek/blast-base-url](https://github.com/mtymek/blast-base-url) -* [ocramius/psr7-session](https://github.com/Ocramius/PSR7Session) -* [oscarotero/psr7-middlewares](https://github.com/oscarotero/psr7-middlewares) -* [php-middleware/block-robots](https://github.com/php-middleware/block-robots) -* [php-middleware/http-authentication](https://github.com/php-middleware/http-authentication) -* [php-middleware/log-http-messages](https://github.com/php-middleware/log-http-messages) -* [php-middleware/maintenance](https://github.com/php-middleware/maintenance) -* [php-middleware/phpdebugbar](https://github.com/php-middleware/phpdebugbar) -* [php-middleware/request-id](https://github.com/php-middleware/request-id) -* [relay/middleware](https://github.com/relayphp/Relay.Middleware) - -The primary downside of this interface is that the while the interface itself is -a callable, there is currently no way to strictly type a closure. - -### 5.2 Single Pass (Lambda) - -The other approach to middleware is much closer to [StackPHP][stackphp] style -and is defined as: - -``` -fn(request, next): response -``` - -Middleware taking this approach generally has the following commonalities: - -* The middleware is defined with a specific interface with a method that takes - the request for processing. -* The middleware is passed 2 arguments during invocation: - 1. An HTTP request message. - 2. A request handler to which the middleware can delegate the responsibility - of producing an HTTP response message. - -In this form, middleware has no access to a response until one is generated by -the request handler. Middleware can then modify the response before returning it. - -This approach is often referred to as "single pass" or "lambda" in reference to -only the request being passed to the middleware. - -#### 5.2.1 Projects Using Single Pass - -There are fewer examples of this approach within projects using HTTP messages, -with one notable exception. - -[Guzzle middleware][guzzle-middleware] is focused on outgoing (client) requests -and uses this signature: - -```php -function (RequestInterface $request, array $options): ResponseInterface -``` - -#### 5.2.2 Additional Projects Using Single Pass - -There are also significant projects that predate HTTP messages using this approach. - -[StackPHP][stackphp] is based on [Symfony HttpKernel][httpkernel] and supports -middleware with this signature: - -```php -function handle(Request $request, $type, $catch): Response -``` - -_Note: While Stack has multiple arguments, a response object is not included._ - -[Laravel middleware][laravel-middleware] uses Symfony components and supports -middleware with this signature: - -```php -function handle(Request $request, callable $next): Response -``` - -[guzzle-middleware]: http://docs.guzzlephp.org/en/latest/handlers-and-middleware.html -[httpkernel]: https://symfony.com/doc/2.0/components/http_kernel/introduction.html -[laravel-middleware]: https://laravel.com/docs/master/middleware - -### 5.3 Comparison of Approaches - -The single pass approach to middleware has been well established in the PHP -community for many years. This is most evident with the large number of packages -that are based around StackPHP. - -The double pass approach is much newer but has been almost universally used by -early adopters of HTTP messages (PSR-7). - -### 5.4 Chosen Approach - -Despite the nearly universal adoption of the double-pass approach, there are -significant issues regarding implementation. - -The most severe is that passing an empty response has no guarantees that the -response is in a usable state. This is further exacerbated by the fact that a -middleware may modify the response before passing it for further processing. - -Further compounding the problem is that there is no way to ensure that the -response body has not been written to, which can lead to incomplete output or -error responses being sent with cache headers attached. It is also possible -to end up with [corrupted body content][rob-allen-filtering] when writing over -existing body content if the new content is shorter than the original. The most -effective way to resolve these issues is to always provide a fresh stream when -modifying the body of a message. - -[rob-allen-filtering]: https://akrabat.com/filtering-the-psr-7-body-in-middleware/ - -Some have argued that passing the response helps ensure dependency inversion. -While it is true that it helps avoid depending on a specific implementation of -HTTP messages, the problem can also be resolved by injecting factories into the -middleware to create HTTP message objects, or by injecting empty message instances. -With the creation of HTTP Factories in [PSR-17][psr17], a standard approach to -handling dependency inversion is possible. - -[psr17]: https://github.com/php-fig/fig-standards/blob/master/proposed/http-factory/http-factory-meta.md - -A more subjective, but also important, concern is that existing double-pass -middleware typically uses the `callable` type hint to refer to middleware. -This makes strict typing impossible, as there is no assurance that the `callable` -being passed implements a middleware signature, which reduces runtime safety. - -**Due to these significant issues, the lambda approach has been chosen for this proposal.** - -## 6. Design Decisions - -### 6.1 Request Handler Design - -The `RequestHandlerInterface` defines a single method that accepts a request and -MUST return a response. The request handler MAY delegate to another handler. - -#### Why is a server request required? - -To make it clear that the request handler can only be used in a server side context. -In an client side context, a [promise][promises] would likely be returned instead -of a response. - -[promises]: https://promisesaplus.com/ - -#### Why the term "handler"? - -The term "handler" means something designated to manage or control. In terms of -request processing, a request handler is the point where the request must be -acted upon to create a response. - -As opposed to the term "delegate", which was used in a previous version of this -specification, the internal behavior of this interface is not specified. -As long as the request handler ultimately produces a response, it is valid. - -#### Why doesn't request handler use `__invoke`? - -Using `__invoke` is less transparent than using a named method. It also makes -it easier to call the request handler when it is assigned to a class variable, -without using `call_user_func` or other less common syntax. - -_See "discussion of FrameInterface" in [relevant links](#9-relevant-links) for - additional information._ - -### 6.2 Middleware Design - -The `MiddlewareInterface` defines a single method that accepts an HTTP request -and a request handler and must return a response. The middleware may: - -- Evolve the request before passing it to the request handler. -- Evolve the response received from the request handler before returning it. -- Create and return a response without passing the request to the request handler, - thereby handling the request itself. - -When delegating from one middleware to another in a sequence, one approach for -dispatching systems is to use an intermediary request handler composing the -middleware sequence as a way to link middleware together. The final or innermost -middleware will act as a gateway to application code and generate a response -from its results; alternately, the middleware MAY delegate this responsibility -to a dedicated request handler. - -#### Why doesn't middleware use `__invoke`? - -Doing so would conflict with existing middleware that implements the double-pass -approach and may want to implement the middleware interface for purposes of -forward compatibility with this specification. - -#### Why the name `process()`? - -We reviewed a number of existing monolithic and middleware frameworks to -determine what method(s) each defined for processing incoming requests. We found -the following were commonly used: - -- `__invoke` (within middleware systems, such as Slim, Expressive, Relay, etc.) -- `handle` (in particular, software derived from Symfony's [HttpKernel][HttpKernel]) -- `dispatch` (Zend Framework's [DispatchableInterface][DispatchableInterface]) - -[HttpKernel]: https://symfony.com/doc/current/components/http_kernel.html -[DispatchableInterface]: https://github.com/zendframework/zend-stdlib/blob/980ce463c29c1a66c33e0eb67961bba895d0e19e/src/DispatchableInterface.php - -We chose to allow a forward-compatible approach for such classes to repurpose -themselves as middleware (or middleware compatible with this specification), -and thus needed to choose a name not in common usage. As such, we chose -`process`, to indicate _processing_ a request. - -#### Why is a server request required? - -To make it clear that the middleware can only be used in a synchronous, server -side context. - -While not all middleware will need to use the additional methods defined by the -server request interface, outbound requests are typically processed asynchronously -and would typically return a [promise][promises] of a response. (This is primarily -due to the fact that multiple requests can be made in parallel and processed as -they are returned.) It is outside the scope of this proposal to address the needs -of asynchronous request/response life cycles. - -Attempting to define client middleware would be premature at this point. Any future -proposal that is focused on client side request processing should have the opportunity -to define a standard that is specific to the nature of asynchronous middleware. - -_See "client vs server side middleware" in [relevant links](#9-relevant-links) for -additional information._ - -#### What is the role of the request handler? - -Middleware has the following roles: - -- Producing a response on its own. If specific request conditions are met, the - middleware can produce and return a response. - -- Returning the result of the request handler. In cases where the middleware - cannot produce its own response, it can delegate to the request handler to - produce one; sometimes this may involve providing a transformed request (e.g., - to inject a request attribute, or the results of parsing the request body). - -- Manipulating and returning the response produced by the request handler. In - some cases, the middleware may be interested in manipulating the response - the request handler returns (e.g., to gzip the response body, to add CORS - headers, etc.). In such cases, the middleware will capture the response - returned by the request handler, and return a transformed response on - completion. - -In these latter two cases, the middleware may have code such as the following: - -```php -// Straight delegation: -return $handler->handle($request); - -// Capturing the response to manipulate: -$response = $handler->handle($request); -``` - -How the handler acts is entirely up to the developer, so long as it produces a -response. - -In one common scenario, the handler implements a _queue_ or a _stack_ of -middleware instances internally. In such cases, calling -`$handler->handle($request)` will advance the internal pointer, pull the -middleware associated with that pointer, and call it using -`$middleware->process($request, $this)`. If no more middleware exists, it will -generally either raise an exception or return a canned response. - -Another possibility is for _routing middleware_ that matches the incoming -server request to a specific handler, and then returns the response generated by -executing that handler. If unable to route to a handler, it would instead -execute the handler provided to the middleware. (This sort of mechanism can even -be used in conjunction with middleware queues and stacks.) - -### 6.3 Example Interface Interactions - -The two interfaces, `RequestHandlerInterface` and `MiddlewareInterface`, were -designed to work in conjunction with one another. Middleware gains flexibility -when de-coupled from any over-arching application layer, and instead only -relying on the provided request handler to produce a response. - -Two approaches to middleware dispatch systems that the Working Group observed -and/or implemented are demonstrated below. Additionally, examples of re-usable -middleware are provided to demonstrate how to write middleware that is -loosely-coupled. - -Please note that these are not suggested as definitive or exclusive approaches -to defining middleware dispatch systems. - -#### Queue-based request handler - -In this approach, a request handler maintains a queue of middleware, and a -fallback response to return if the queue is exhausted without returning a -response. When executing the first middleware, the queue passes itself as a -request handler to the middleware. - -```php -class QueueRequestHandler implements RequestHandlerInterface -{ - private $middleware = []; - private $fallbackHandler; - - public function __construct(RequestHandlerInterface $fallbackHandler) - { - $this->fallbackHandler = $fallbackHandler; - } - - public function add(MiddlewareInterface $middleware) - { - $this->middleware[] = $middleware; - } - - public function handle(ServerRequestInterface $request): ResponseInterface - { - // Last middleware in the queue has called on the request handler. - if (0 === count($this->middleware)) { - return $this->fallbackHandler->handle($request); - } - - $middleware = array_shift($this->middleware); - return $middleware->process($request, $this); - } -} -``` - -An application bootstrap might then look like this: - -```php -// Fallback handler: -$fallbackHandler = new NotFoundHandler(); - -// Create request handler instance: -$app = new QueueRequestHandler($fallbackHandler); - -// Add one or more middleware: -$app->add(new AuthorizationMiddleware()); -$app->add(new RoutingMiddleware()); - -// execute it: -$response = $app->handle(ServerRequestFactory::fromGlobals()); -``` - -This system has two request handlers: one that will produce a response if the -last middleware delegates to the request handler, and one for dispatching the -middleware layers. (In this example, the `RoutingMiddleware` will likely execute -composed handlers on a successful route match; see more on that below.) - -This approach has the following benefits: - -- Middleware does not need to know anything about any other middleware or how it - is composed in the application. -- The `QueueRequestHandler` is agnostic of the PSR-7 implementation in use. -- Middleware is executed in the order it is added to the application, making the - code explicit. -- Generation of the "fallback" response is delegated to the application - developer. This allows the developer to determine whether that should be a - "404 Not Found" condition, a default page, etc. - -#### Decoration-based request handler - -In this approach, a request handler implementation decorates both a middleware -instance and a fallback request handler to pass to it. The application is built -from the outside-in, passing each request handler "layer" to the next outer one. - -```php -class DecoratingRequestHandler implements RequestHandlerInterface -{ - private $middleware; - private $nextHandler; - - public function __construct(MiddlewareInterface $middleware, RequestHandlerInterface $nextHandler) - { - $this->middleware = $middleware; - $this->nextHandler = $nextHandler; - } - - public function handle(ServerRequestInterface $request): ResponseInterface - { - return $this->middleware->process($request, $this->nextHandler); - } -} - -// Create a response prototype to return if no middleware can produce a response -// on its own. This could be a 404, 500, or default page. -$responsePrototype = (new Response())->withStatus(404); -$innerHandler = new class ($responsePrototype) implements RequestHandlerInterface { - private $responsePrototype; - - public function __construct(ResponseInterface $responsePrototype) - { - $this->responsePrototype = $responsePrototype; - } - - public function handle(ServerRequestInterface $request): ResponseInterface - { - return $this->responsePrototype; - } -}; - -$layer1 = new DecoratingRequestHandler(new RoutingMiddleware(), $innerHandler); -$layer2 = new DecoratingRequestHandler(new AuthorizationMiddleware(), $layer1); - -$response = $layer2->handle(ServerRequestFactory::fromGlobals()); -``` - -Similar to the queue-based middleware, request handlers serve two purposes in -this system: - -- Producing a fallback response if no other layer does. -- Dispatching middleware. - -#### Reusable Middleware Examples - -In the examples above, we have two middleware composed in each. In order for -these to work in either situation, we need to write them such that they interact -appropriately. - -Implementors of middleware striving for maximum interoperability may want to -consider the following guidelines: - -- Test the request for a required condition. If it does not satisfy that - condition, use a composed prototype response or a composed response factory - to generate and return a response. - -- If pre-conditions are met, delegate creation of the response to the provided - request handler, optionally providing a "new" request by manipulating the - provided request (e.g., `$handler->handle($request->withAttribute('foo', - 'bar')`). - -- Either pass the response returned by the request handler unaltered, or provide - a new response by manipulating the one returned (e.g., `return - $response->withHeader('X-Foo-Bar', 'baz')`). - -The `AuthorizationMiddleware` is one that will exercise all three of these guidelines: - -- If authorization is required, but the request is not authorized, it will use a - composed prototype response to produce an "unauthorized" response. -- If authorization is not required, it will delegate the request to the handler - without changes. -- If authorization is required and the request is authorized, it will delegate - the request to the handler, and sign the response returned based on the request. - -```php -class AuthorizationMiddleware implements MiddlewareInterface -{ - private $authorizationMap; - - public function __construct(AuthorizationMap $authorizationMap) - { - $this->authorizationMap = $authorizationMap; - } - - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface - { - if (! $authorizationMap->needsAuthorization($request)) { - return $handler->handle($request); - } - - if (! $authorizationMap->isAuthorized($request)) { - return $authorizationMap->prepareUnauthorizedResponse(); - } - - $response = $handler->handle($request); - return $authorizationMap->signResponse($response, $request); - } -} -``` - -Note that the middleware is not concerned with how the request handler is -implemented; it merely uses it to produce a response when pre-conditions have -been met. - -The `RoutingMiddleware` implementation described below follows a similar -process: it analyzes the request to see if it matches known routes. In this -particular implementation, routes map to request handlers, and the middleware -essentially delegates to them in order to produce a response. However, in the -case that no route is matched, it will execute the handler passed to it to -produce the response to return. - -```php -class RoutingMiddleware implements MiddlewareInterface -{ - private $router; - - public function __construct(Router $router) - { - $this->router = $router; - } - - public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface - { - $result = $this->router->match($request); - - if ($result->isSuccess()) { - return $result->getHandler()->handle($request); - } - - return $handler->handle($request); - } -} -``` - -## 7. People - -This PSR was produced by a FIG Working Group with the following members: - -* Matthew Weier O'Phinney (sponsor), -* Woody Gilk (editor), -* Glenn Eggleton -* Matthieu Napoli -* Oscar Otero -* Korvin Szanto -* Stefano Torresi - -The working group would also like to acknowledge the contributions of: - -* Jason Coward, -* Paul M. Jones, -* Rasmus Schultz, - -## 8. Votes - -* [Working Group Formation](https://groups.google.com/d/msg/php-fig/rPFRTa0NODU/tIU9BZciAgAJ) -* [Review Period Initiation](https://groups.google.com/d/msg/php-fig/mfTrFinTvEM/PiYvU2S6BAAJ) -* [Acceptance](https://groups.google.com/d/msg/php-fig/bhQmHt39hJE/ZCYrK_O2AQAJ) - -## 9. Relevant Links - -_**Note:** Order descending chronologically._ - -* [PHP-FIG mailing list thread](https://groups.google.com/d/msg/php-fig/vTtGxdIuBX8/NXKieN9vDQAJ) -* [The PHP League middleware proposal](https://groups.google.com/d/msg/thephpleague/jyztj-Nz_rw/I4lHVFigAAAJ) -* [PHP-FIG discussion of FrameInterface](https://groups.google.com/d/msg/php-fig/V12AAcT_SxE/aRXmNnIVCwAJ) -* [PHP-FIG discussion about client vs server side middleware](https://groups.google.com/d/msg/php-fig/vBk0BRgDe2s/GTaT0yKNBgAJ) - -## 10. Errata - -... diff --git a/_docs/psr/PSR-16-simple-cache-meta.md b/_docs/psr/PSR-16-simple-cache-meta.md new file mode 100644 index 0000000..9eb37b6 --- /dev/null +++ b/_docs/psr/PSR-16-simple-cache-meta.md @@ -0,0 +1,70 @@ +# PSR-16 Meta Document + +## 1. Summary + +Caching is a common way to improve the performance of any project, and many +libraries make use or could make use of it. Interoperability at this level +means libraries can drop their own caching implementations and easily rely +on the one given to them by the framework, or another dedicated cache +library the user picked. + +## 2. Why Bother? + +PSR-6 solves this problem already, but in a rather formal and verbose way for +what the most simple use cases need. This simpler approach aims to build a +standardized layer of simplicity on top of the existing PSR-6 interfaces. + +## 3. Scope + +### 3.1 Goals + +* A simple interface for cache operations. +* Basic support for operations on multiple keys for performance (round-trip-time) + reasons. +* Providing an adapter class that turns a PSR-6 implementation into a + PSR-Simple-Cache one. +* It should be possible to expose both caching PSRs from a caching library. + +### 3.2 Non-Goals + +* Solving all possible edge cases, PSR-6 does this well already. + +## 4. Approaches + +The approach chosen here is very barebones by design, as it is to be used +only by the most simple cases. It does not have to be implementable by all +possible cache backends, nor be usable for all usages. It is merely a layer +of convenience on top of PSR-6. + +## 5. People + +### 5.1 Editor(s) + +* Paul Dragoonis (@dragoonis) + +### 5.2 Sponsors + +* Jordi Boggiano (@seldaek) - Composer (Coordinator) +* Fabien Potencier (@fabpot) - Symfony + +### 5.3 Contributors + +For their role in the writing the initial version of this cache PSR: + +* Evert Pot (@evert) +* Florin Pățan (@dlsniper) + +For being an early reviewer + +* Daniel Messenger (@dannym87) + +## 6. Votes + +* **Entrance Vote:** https://groups.google.com/d/topic/php-fig/vyQTKHS6pJ8/discussion +* **Acceptance Vote:** https://groups.google.com/d/msg/php-fig/A8e6GvDRGIk/HQBJGEhbDQAJ + +## 7. Relevant Links + +* [Survey of existing cache implementations][1], by @dragoonis + +[1]: https://docs.google.com/spreadsheet/ccc?key=0Ak2JdGialLildEM2UjlOdnA4ekg3R1Bfeng5eGlZc1E#gid=0 diff --git a/_docs/psr/PSR-16-simple-cache.md b/_docs/psr/PSR-16-simple-cache.md index dff9960..3308672 100644 --- a/_docs/psr/PSR-16-simple-cache.md +++ b/_docs/psr/PSR-16-simple-cache.md @@ -1,18 +1,5 @@ ---- -title: PRS-16 -category: PSRs -order: 10 ---- - -| Informações Adicionais | -| ----------------------------------------------------------------------------------| -| [Common Interface for Caching Libraries][Common Interface for Caching Libraries] | -| [Meta Document][Meta Document] | - -[Common Interface for Caching Libraries]: #Common Interface for Caching Libraries -[Meta Document]: #Meta Document - -

Common Interface for Caching Libraries

+Common Interface for Caching Libraries +====================================== This document describes a simple yet extensible interface for a cache item and a cache driver. @@ -39,7 +26,7 @@ framework, or another dedicated cache library. PSR-6 solves this problem already, but in a rather formal and verbose way for what the most simple use cases need. This simpler approach aims to build a -standardized streamlined interface for common cases. It is independent of +standardized streamlined interface for common cases. It is independent of PSR-6 but has been designed to make compatibility with PSR-6 as straightforward as possible. @@ -83,8 +70,8 @@ by an integer representing time in seconds, or a DateInterval object. cached item. Implementing libraries MUST support keys consisting of the characters `A-Z`, `a-z`, `0-9`, `_`, and `.` in any order in UTF-8 encoding and a length of up to 64 characters. Implementing libraries MAY support additional -characters and encodings or longer lengths, but must support at least that -minimum. Libraries are responsible for their own escaping of key strings +characters and encodings or longer lengths, but MUST support at least that +minimum. Libraries are responsible for their own escaping of key strings as appropriate, but MUST be able to return the original unmodified key string. The following characters are reserved for future extensions and MUST NOT be supported by implementing libraries: `{}()/\@:` @@ -98,9 +85,9 @@ assumptions. ## 1.3 Cache Implementations MAY provide a mechanism for a user to specify a default TTL -if one is not specified for a specific cache item. If no user-specified default +if one is not specified for a specific cache item. If no user-specified default is provided implementations MUST default to the maximum legal value allowed by -the underlying implementation. If the underlying implementation does not +the underlying implementation. If the underlying implementation does not support TTL, the user-specified TTL MUST be silently ignored. ## 1.4 Data @@ -110,18 +97,18 @@ Implementing libraries MUST support all serializable PHP data types, including: * **Strings** - Character strings of arbitrary size in any PHP-compatible encoding. * **Integers** - All integers of any size supported by PHP, up to 64-bit signed. * **Floats** - All signed floating point values. -* **Boolean** - True and False. +* **Booleans** - True and False. * **Null** - The null value (although it will not be distinguishable from a cache miss when reading it back out). * **Arrays** - Indexed, associative and multidimensional arrays of arbitrary depth. -* **Object** - Any object that supports lossless serialization and +* **Objects** - Any object that supports lossless serialization and deserialization such that $o == unserialize(serialize($o)). Objects MAY leverage PHP's Serializable interface, `__sleep()` or `__wakeup()` magic methods, or similar language functionality if appropriate. All data passed into the Implementing Library MUST be returned exactly as passed. That includes the variable type. That is, it is an error to return -(string) 5 if (int) 5 was the value saved. Implementing Libraries MAY use PHP's +(string) 5 if (int) 5 was the value saved. Implementing Libraries MAY use PHP's serialize()/unserialize() functions internally but are not required to do so. Compatibility with them is simply used as a baseline for acceptable object values. @@ -135,13 +122,13 @@ libraries MUST respond with a cache miss rather than corrupted data. The cache interface defines the most basic operations on a collection of cache-entries, which entails basic reading, writing and deleting individual cache items. -In addition it has methods for dealing with multiple sets of cache entries such as writing, reading or +In addition, it has methods for dealing with multiple sets of cache entries such as writing, reading or deleting multiple cache entries at a time. This is useful when you have lots of cache reads/writes to perform, and lets you perform your operations in a single call to the cache server cutting down latency times dramatically. An instance of CacheInterface corresponds to a single collection of cache items with a single key namespace, -and is equivalent to a "Pool" in PSR-6. Different CacheInterface instances MAY be backed by the same +and is equivalent to a "Pool" in PSR-6. Different CacheInterface instances MAY be backed by the same datastore, but MUST be logically independent. ~~~php @@ -168,7 +155,7 @@ interface CacheInterface * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time. * * @param string $key The key of the item to store. - * @param mixed $value The value of the item to store, must be serializable. + * @param mixed $value The value of the item to store. Must be serializable. * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and * the driver supports TTL then the library may set a default value * for it or let the driver take care of that. @@ -248,7 +235,7 @@ interface CacheInterface * NOTE: It is recommended that has() is only to be used for cache warming type purposes * and not to be used within your live applications operations for get/set, as this method * is subject to a race condition where your has() will return true and immediately after, - * another script can remove it making the state of your app out of date. + * another script can remove it, making the state of your app out of date. * * @param string $key The cache item key. * @@ -287,89 +274,10 @@ namespace Psr\SimpleCache; /** * Exception interface for invalid cache arguments. * - * When an invalid argument is passed it must throw an exception which implements - * this interface + * When an invalid argument is passed, it must throw an exception which implements + * this interface. */ interface InvalidArgumentException extends CacheException { } ~~~ - - -

Meta Document

- -1. Summary ----------- - -Caching is a common way to improve the performance of any project, and many -libraries make use or could make use of it. Interoperability at this level -means libraries can drop their own caching implementations and easily rely -on the one given to them by the framework, or another dedicated cache -library the user picked. - -2. Why Bother? --------------- - -PSR-6 solves this problem already, but in a rather formal and verbose way for -what the most simple use cases need. This simpler approach aims to build a -standardized layer of simplicity on top of the existing PSR-6 interfaces. - -3. Scope --------- - -### 3.1 Goals - -* A simple interface for cache operations. -* Basic support for operations on multiple keys for performance (round-trip-time) - reasons. -* Providing an adapter class that turns a PSR-6 implementation into a - PSR-Simple-Cache one. -* It should be possible to expose both caching PSRs from a caching library. - -### 3.2 Non-Goals - -* Solving all possible edge cases, PSR-6 does this well already. - -4. Approaches -------------- - -The approach chosen here is very barebones by design, as it is to be used -only by the most simple cases. It does not have to be implementable by all -possible cache backends, nor be usable for all usages. It is merely a layer -of convenience on top of PSR-6. - -5. People ---------- - -### 5.1 Editor(s) - -* Paul Dragoonis (@dragoonis) - -### 5.2 Sponsors - -* Jordi Boggiano (@seldaek) - Composer (Coordinator) -* Fabien Potencier (@fabpot) - Symfony - -### 5.3 Contributors - -For their role in the writing the initial version of this cache PSR: - -* Evert Pot (@evert) -* Florin Pățan (@dlsniper) - -For being an early reviewer - -* Daniel Messenger (@dannym87) - -6. Votes --------- - -* **Entrance Vote:** https://groups.google.com/d/topic/php-fig/vyQTKHS6pJ8/discussion -* **Acceptance Vote:** https://groups.google.com/d/msg/php-fig/A8e6GvDRGIk/HQBJGEhbDQAJ - -7. Relevant Links ------------------ - -* [Survey of existing cache implementations][1], by @dragoonis - -[1]: https://docs.google.com/spreadsheet/ccc?key=0Ak2JdGialLildEM2UjlOdnA4ekg3R1Bfeng5eGlZc1E#gid=0 diff --git a/_docs/psr/PSR-17-http-factory-meta.md b/_docs/psr/PSR-17-http-factory-meta.md new file mode 100644 index 0000000..97679e1 --- /dev/null +++ b/_docs/psr/PSR-17-http-factory-meta.md @@ -0,0 +1,308 @@ +HTTP Factories Meta +=================== + +## 1. Summary + +The purpose of this PSR is to provide factory interfaces that define methods to +create [PSR-7][psr7] objects. + +[psr7]: https://www.php-fig.org/psr/psr-7/ + +## 2. Why Bother? + +The current specification for PSR-7 allows for most objects to be modified by +creating immutable copies. However, there are two notable exceptions: + +- `StreamInterface` is a mutable object based on a resource that only allows + the resource to be written to when the resource is writable. +- `UploadedFileInterface` is a read-only object based on a resource that offers + no modification capabilities. + +The former is a significant pain point for PSR-7 middleware, as it can leave +the response in an incomplete state. If the stream attached to the response body +is not seekable or not writable, there is no way to recover from an error +condition in which the body has already been written to. + +This scenario can be avoided by providing a factory to create new streams. Due to +the lack of a formal standard for HTTP object factories, a developer must rely on +a specific vendor implementation in order to create these objects. + +Another pain point is when writing re-usable middleware or request handlers. In +such cases, package authors may need to create and return a response. However, +creating discrete instances then ties the package to a specific PSR-7 +implementation. If these packages rely on the request factory interface instead, +they can remain agnostic of the PSR-7 implementation. + +Creating a formal standard for factories will allow developers to avoid +dependencies on specific implementations while having the ability to create new +objects when necessary. + +## 3. Scope + +### 3.1 Goals + +- Provide a set of interfaces that define methods to create PSR-7 compatible objects. + +### 3.2 Non-Goals + +- Provide a specific implementation of PSR-7 factories. + +## 4. Approaches + +### 4.1 Chosen Approach + +The factory method definition has been chosen based on whether or not the object +can be modified after instantiation. For interfaces that cannot be modified, all +of the object properties must be defined at the time of instantiation. + +In the case of `UriInterface` a complete URI may be passed for convenience. + +The method names used will not conflict. This allows for a single class to +implement multiple interfaces when appropriate. + +### 4.2 Existing Implementations + +All of the current implementations of PSR-7 have defined their own requirements. +In most cases, the required parameters are the same or less strict than the proposed +factory methods. + +#### 4.2.1 Diactoros + +[Diactoros][zend-diactoros] was one of the first HTTP Messages implementations for +server usage, and was developed parallel to the PSR-7 specification. + +- [`Request`][diactoros-request] No required parameters, method and URI default to `null`. +- [`Response`][diactoros-response] No required parameters, status code defaults to `200`. +- [`ServerRequest`][diactoros-server-request] No required parameters. Contains a separate + [`ServerRequestFactory`][diactoros-server-request-factory] for creating requests from globals. +- [`Stream`][diactoros-stream] Requires `string|resource $stream` for the body. +- [`UploadedFile`][diactoros-uploaded-file] Requires `string|resource $streamOrFile`, `int $size`, + `int $errorStatus`. Error status must be a PHP upload constant. +- [`Uri`][diactoros-uri] No required parameters, `string $uri` is empty by default. + +[zend-diactoros]: https://docs.zendframework.com/zend-diactoros/ +[diactoros-request]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Request.php#L33 +[diactoros-response]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Response.php#L114 +[diactoros-server-request]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/ServerRequest.php#L78-L89 +[diactoros-server-request-factory]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/ServerRequestFactory.php#L52-L58 +[diactoros-stream]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Stream.php#L36 +[diactoros-uploaded-file]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/UploadedFile.php#L62 +[diactoros-uri]: https://github.com/zendframework/zend-diactoros/blob/b4e7758556c97b5bb9a5260d898e9788ee800538/src/Uri.php#L94 + +Overall this approach is quite similar to the proposed factories. In some cases, +more options are given by Diactoros which are not required for a valid object. +The proposed uploaded file factory allows for size and error status to be optional. + +#### 4.2.2 Guzzle + +[Guzzle][guzzle] is an HTTP Messages implementation that focuses on client usage. + +- [`Request`][guzzle-request] Requires both `string $method` and `string|UriInterface $uri`. +- [`Response`][guzzle-response] No required parameters, status code defaults to `200`. +- [`Stream`][guzzle-stream] Requires `resource $stream` for the body. +- [`Uri`][guzzle-uri] No required parameters, `string $uri` is empty by default. + +_Being geared towards client usage, Guzzle does not contain a `ServerRequest` or +`UploadedFile` implementation._ + +[guzzle]: https://github.com/guzzle/psr7 +[guzzle-request]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Request.php#L32-L38 +[guzzle-response]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Response.php#L88-L94 +[guzzle-stream]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Stream.php#L51 +[guzzle-uri]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/Uri.php#L48 + +Overall this approach is also quite similar to the proposed factories. One notable +difference is that Guzzle requires streams to be constructed with a resource and +does not allow a string. However, it does contain a helper function [`stream_for`][guzzle-stream-for] +that will create a stream from a string of content and a function [`try_fopen`][guzzle-try-fopen] +that will create a resource from a file path. + +[guzzle-stream-for]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/functions.php#L78 +[guzzle-try-fopen]: https://github.com/guzzle/psr7/blob/58828615f7bb87013ce6365e9b1baa08580c7fc8/src/functions.php#L295 + +#### 4.2.3 Slim + +[Slim][slim] is a micro-framework that makes use of HTTP Messages from version +3.0 forward. + +- [`Request`][slim-request] Requires `string $method`, `UriInterface $uri`, + `HeadersInterface $headers`, `array $cookies`, `array $serverParams`, and + `StreamInterface $body`. Contains a factory method `createFromEnvironment(Environment $environment)` + that is framework specific but analogous to the proposed `createServerRequestFromArray`. +- [`Response`][slim-response] No required parameters, status code defaults to `200`. +- [`Stream`][slim-stream] Requires `resource $stream` for the body. +- [`UploadedFile`][slim-uploaded-file] Requires `string $file` for the source file. + Contains a factory method `parseUploadedFiles(array $uploadedFiles)` for creating + an array of `UploadedFile` instances from `$_FILES` or similar format. Also contains + a factory method `createFromEnvironment(Environment $env)` that is framework specific + and makes use of `parseUploadedFiles`. +- [`Uri`][slim-uri] Requires `string $scheme` and `string $host`. Contains a factory + method `createFromString($uri)` that can be used to create a `Uri` from a string. + +_Being geared towards server usage only, Slim does not contain an implementation +of `Request`. The implementation listed above is an implementation of `ServerRequest`._ + +[slim]: https://www.slimframework.com/ +[slim-request]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Request.php#L170-L178 +[slim-response]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Response.php#L123 +[slim-stream]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Stream.php#L96 +[slim-uploaded-file]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/UploadedFile.php#L151 +[slim-uri]: https://github.com/slimphp/Slim/blob/30cfe3c07dac28ec1129c0577e64b90ba11a54c4/Slim/Http/Uri.php#L112-L121 + +Of the compared approaches, Slim is most different from the proposed factories. +Most notably, the `Request` implementation contains requirements specific +to the framework that are not defined in HTTP Messages specification. The factory +methods that are included are generally similar with the proposed factories. + +### 4.3 Potential Issues + +The most difficult task in establishing this standard will be defining the +method signatures for the interfaces. As there is no clear declaration in PSR-7 +as to what values are explicitly required, the properties that are read-only +must be inferred based on whether the interfaces have methods to copy-and-modify +the object. + +## 5. Design Decisions + +### 5.1 Why PHP 7? + +While PSR-7 does not target PHP 7, the authors of this specification note that, +at the time of writing (April 2018), PHP 5.6 stopped receiving bugfixes 15 +months ago, and will no longer receive security patches in 8 months; PHP 7.0 +itself will stop receiving security fixes in 7 months (see the [PHP supported +versions document][php-support] for current support details). Since +specifications are meant to be long-term, the authors feel the specification +should target versions that will be supported for the foreseeable future; PHP 5 +will not. As such, from a security standpoint, targeting anything under PHP 7 is +a disservice to users, as doing so would be tacit approval of usage of +unsupported PHP versions. + +Additionally, and equally importantly, PHP 7 gives us the ability to provide +return type hints to interfaces we define. This guarantees a strong, +predicatable contract for end users, as they can assume that the values returned +by implementations will be exactly what they expect. + +[php-support]: http://php.net/supported-versions.php + +### 5.2 Why multiple interfaces? + +Each proposed interface is (primarily) responsible for producing one PSR-7 type. +This allows consumers to typehint on exactly what they need: if they need a +response, they typehint on `ResponseFactoryInterface`; if they need a URI, they +typehint on `UriFactoryInterface`. In this way, users can be granular about what +they need. + +Doing so also allows application developers to provide anonymous implementations +based on the PSR-7 implementation they are using, producing only the instances +they need for the specific context. This reduces boilerplate; developers do not +need to write stubs for unused methods. + +### 5.3 Why does the $reasonPhrase argument to the ResponseFactoryInterface exist? + +`ResponseFactoryInterface::createResponse()` includes an optional string +argument, `$reasonPhrase`. In the PSR-7 specification, you can only provide a +reason phrase at the same time you provide a status code, as the two are related +pieces of data. The authors of this specification have chosen to mimic the PSR-7 +`ResponseInterface::withStatus()` signature to ensure both sets of data may be +present in the response created. + +### 5.4 Why does the $serverParams argument to the ServerRequestFactoryInterface exist? + +`ServerRequestFactoryInterface::createServerRequest()` includes an optional +`$serverParams` array argument. The reason this is provided is to ensure that an +instance can be created with the server params populated. Of the data accessible +via the `ServerRequestInterface`, the only data that does not have a mutator +method is the one corresponding to the server params. As such, this data MUST be +provided at initial creation. For this reason, it exists as an argument to the +factory method. + +### 5.5 Why is there no factory for creating a ServerRequestInterface from superglobals? + +The primary use case of `ServerRequestFactoryInterface` is for creating a new +`ServerRequestInterface` instance from known data. Any solution around +marshaling data from superglobals assumes that: + +- superglobals are present +- superglobals follow a specific structure + +These two assumptions are not always true. When using asynchronous systems such +as [Swoole][swoole], [ReactPHP][reactphp], and others: + +- will not populate standard superglobals such as `$_GET`, `$_POST`, `$_COOKIE`, + and `$_FILES` +- will not populate `$_SERVER` with the same elements as a standard SAPI (such as + mod_php, mod-cgi, and mod-fpm) + +Moreover, different standard SAPIs provide different information to `$_SERVER` +and access to request headers, requiring different approaches for initial +population of the request. + +As such, designing an interface for population of an instance from superglobals +is out of scope of this specification, and should largely be +implementation-specfic. + +[swoole]: https://www.swoole.co.uk/ +[reactphp]: https://reactphp.org/ + +### 5.6 Why does RequestFactoryInterface::createRequest allow a string URI? + +The primary use case of `RequestFactoryInterface` is to create a request, and +the only required values for any request are the request method and a URI. While +`RequestFactoryInterface::createRequest()` can accept a `UriInterface` instance, +it also allows a string. + +The rationale is two-fold. First, the majority use case is to create a request +instance; creation of the URI instance is secondary. Requiring a `UriInterface` +means users would either need to also have access to a `UriFactoryInterface`, or +the `RequestFactoryInterface` would have a hard requirement on a +`UriFactoryInterface`. The first complicates usage for consumers of the factory, +the second complicates usage for either developers of the factory, or those +creating the factory instance. + +Second, `UriFactoryInterface` provides exactly one way to create a +`UriInterface` instance, and that is from a string URI. If creation of the URI +is based on a string, there's no reason for the `RequestFactoryInterface` not to +allow the same semantics. Additionally, every PSR-7 implementation surveyed at +the time this proposal was developed allowed a string URI when creating a +`RequestInterface` instance, as the value was then passed to whatever +`UriInterface` implementation they provided. As such, accepting a string is +expedient and follows existing semantics. + +## 6. People + +This PSR was produced by a FIG Working Group with the following members: + +- Woody Gilk (editor), +- Matthew Weier O'Phinney (sponsor), +- Stefano Torresi +- Matthieu Napoli +- Korvin Szanto +- Glenn Eggleton +- Oscar Otero +- Tobias Nyholm + +The working group would also like to acknowledge the contributions of: + +- Paul M. Jones, +- Rasmus Schultz, +- Roman Tsjupa, + +## 7. Votes + +- [Entrance Vote](https://groups.google.com/forum/#!topic/php-fig/6rZPZ8VglIM) +- [Working Group Formation](https://groups.google.com/d/msg/php-fig/A5mZYTn5Jm8/j0FN6eZtBAAJ) +- [Review Period Initiation](https://groups.google.com/d/msg/php-fig/OpUnkrnFhe0/y2dT7CakAQAJ) +- [Acceptance Vote](https://groups.google.com/d/msg/php-fig/M8PapGXXE1E/uBq2Dq-ZAwAJ) + +## 8. Relevant Links + +_**Note:** Order descending chronologically._ + +- [PSR-7 Middleware Proposal](https://github.com/php-fig/fig-standards/pull/755) +- [PHP-FIG mailing list discussion of middleware](https://groups.google.com/forum/#!topic/php-fig/vTtGxdIuBX8) +- [ircmaxwell All About Middleware](http://blog.ircmaxell.com/2016/05/all-about-middleware.html) +- [shadowhand All About PSR-7 Middleware](http://shadowhand.me/all-about-psr-7-middleware/) +- [AndrewCarterUK PSR-7 Objects Are Not Immutable](http://andrewcarteruk.github.io/programming/2016/05/22/psr-7-is-not-immutable.html) +- [shadowhand Dependency Inversion and PSR-7 Bodies](http://shadowhand.me/dependency-inversion-and-psr-7-bodies/) +- [PHP-FIG mailing list thread discussing factories](https://groups.google.com/d/msg/php-fig/G5pgQfQ9fpA/UWeM1gm1CwAJ) +- [PHP-FIG mailing list thread feedback on proposal](https://groups.google.com/d/msg/php-fig/piRtB2Z-AZs/8UIwY1RtDgAJ) diff --git a/_docs/psr/PSR-17-http-factory.md b/_docs/psr/PSR-17-http-factory.md new file mode 100644 index 0000000..cf7b31c --- /dev/null +++ b/_docs/psr/PSR-17-http-factory.md @@ -0,0 +1,219 @@ +HTTP Factories +============== + +This document describes a common standard for factories that create [PSR-7][psr7] +compliant HTTP objects. + +PSR-7 did not include a recommendation on how to create HTTP objects, which leads +to difficulties when needing to create new HTTP objects within components that are +not tied to a specific implementation of PSR-7. + +The interfaces outlined in this document describe methods by which PSR-7 objects +can be instantiated. + +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 [RFC 2119][rfc2119]. + +[psr7]: https://www.php-fig.org/psr/psr-7/ +[rfc2119]: https://tools.ietf.org/html/rfc2119 + +## 1. Specification + +An HTTP factory is a method by which a new HTTP object, as defined by PSR-7, +is created. HTTP factories MUST implement these interfaces for each object type +that is provided by the package. + +## 2. Interfaces + +The following interfaces MAY be implemented together within a single class or +in separate classes. + +### 2.1 RequestFactoryInterface + +Has the ability to create client requests. + +```php +namespace Psr\Http\Message; + +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\UriInterface; + +interface RequestFactoryInterface +{ + /** + * Create a new request. + * + * @param string $method The HTTP method associated with the request. + * @param UriInterface|string $uri The URI associated with the request. + */ + public function createRequest(string $method, $uri): RequestInterface; +} +``` + +### 2.2 ResponseFactoryInterface + +Has the ability to create responses. + +```php +namespace Psr\Http\Message; + +use Psr\Http\Message\ResponseInterface; + +interface ResponseFactoryInterface +{ + /** + * Create a new response. + * + * @param int $code The HTTP status code. Defaults to 200. + * @param string $reasonPhrase The reason phrase to associate with the status code + * in the generated response. If none is provided, implementations MAY use + * the defaults as suggested in the HTTP specification. + */ + public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface; +} +``` + +### 2.3 ServerRequestFactoryInterface + +Has the ability to create server requests. + +```php +namespace Psr\Http\Message; + +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\UriInterface; + +interface ServerRequestFactoryInterface +{ + /** + * Create a new server request. + * + * Note that server parameters are taken precisely as given - no parsing/processing + * of the given values is performed. In particular, no attempt is made to + * determine the HTTP method or URI, which must be provided explicitly. + * + * @param string $method The HTTP method associated with the request. + * @param UriInterface|string $uri The URI associated with the request. + * @param array $serverParams An array of Server API (SAPI) parameters with + * which to seed the generated request instance. + */ + public function createServerRequest(string $method, $uri, array $serverParams = []): ServerRequestInterface; +} +``` + +### 2.4 StreamFactoryInterface + +Has the ability to create streams for requests and responses. + +```php +namespace Psr\Http\Message; + +use Psr\Http\Message\StreamInterface; + +interface StreamFactoryInterface +{ + /** + * Create a new stream from a string. + * + * The stream SHOULD be created with a temporary resource. + * + * @param string $content String content with which to populate the stream. + */ + public function createStream(string $content = ''): StreamInterface; + + /** + * Create a stream from an existing file. + * + * The file MUST be opened using the given mode, which may be any mode + * supported by the `fopen` function. + * + * The `$filename` MAY be any string supported by `fopen()`. + * + * @param string $filename The filename or stream URI to use as basis of stream. + * @param string $mode The mode with which to open the underlying filename/stream. + * + * @throws \RuntimeException If the file cannot be opened. + * @throws \InvalidArgumentException If the mode is invalid. + */ + public function createStreamFromFile(string $filename, string $mode = 'r'): StreamInterface; + + /** + * Create a new stream from an existing resource. + * + * The stream MUST be readable and may be writable. + * + * @param resource $resource The PHP resource to use as the basis for the stream. + */ + public function createStreamFromResource($resource): StreamInterface; +} +``` + +Implementations of this interface SHOULD use a temporary stream when creating +resources from strings. The RECOMMENDED method for doing so is: + +```php +$resource = fopen('php://temp', 'r+'); +``` + +### 2.5 UploadedFileFactoryInterface + +Has the ability to create streams for uploaded files. + +```php +namespace Psr\Http\Message; + +use Psr\Http\Message\StreamInterface; +use Psr\Http\Message\UploadedFileInterface; + +interface UploadedFileFactoryInterface +{ + /** + * Create a new uploaded file. + * + * If a size is not provided it will be determined by checking the size of + * the stream. + * + * @link http://php.net/manual/features.file-upload.post-method.php + * @link http://php.net/manual/features.file-upload.errors.php + * + * @param StreamInterface $stream The underlying stream representing the + * uploaded file content. + * @param int $size The size of the file in bytes. + * @param int $error The PHP file upload error. + * @param string $clientFilename The filename as provided by the client, if any. + * @param string $clientMediaType The media type as provided by the client, if any. + * + * @throws \InvalidArgumentException If the file resource is not readable. + */ + public function createUploadedFile( + StreamInterface $stream, + int $size = null, + int $error = \UPLOAD_ERR_OK, + string $clientFilename = null, + string $clientMediaType = null + ): UploadedFileInterface; +} +``` + +### 2.6 UriFactoryInterface + +Has the ability to create URIs for client and server requests. + +```php +namespace Psr\Http\Message; + +use Psr\Http\Message\UriInterface; + +interface UriFactoryInterface +{ + /** + * Create a new URI. + * + * @param string $uri The URI to parse. + * + * @throws \InvalidArgumentException If the given URI cannot be parsed. + */ + public function createUri(string $uri = '') : UriInterface; +} +``` diff --git a/_docs/psr/PSR-18-http-client-meta.md b/_docs/psr/PSR-18-http-client-meta.md new file mode 100644 index 0000000..7daf73a --- /dev/null +++ b/_docs/psr/PSR-18-http-client-meta.md @@ -0,0 +1,148 @@ +HTTP Client Meta Document +========================= + +## Summary + +HTTP requests and responses are the two fundamental objects in web programming. +All clients communicating to an external API use some form of HTTP client. Many +libraries are coupled to one specific client or implement a client and/or +adapter layer themselves. This leads to bad library design, version conflicts, +or code unrelated to the library domain. + +## Why bother? + +Thanks to PSR-7 we know how HTTP requests and responses ideally look, but nothing +defines how a request should be sent and a response received. A common interface for HTTP +clients will allow libraries to be decoupled from specific implementations. + +## Scope + +### Goals + +* A common interface for sending PSR-7 messages and returning PSR-7 responses. + +### Non-Goals + +* Support for asynchronous HTTP requests is left for another future PSR. +* This PSR does not define how to configure an HTTP client. It only specifies the + default behaviours. +* This PSR is neutral about the use of middleware. + +#### Asynchronous HTTP client + +The reason asynchronous requests are not covered by this PSR is the lack of a +common standard for Promises. Promises are sufficiently complex enough that they +deserve their own specification, and should not be wrapped into this one. + +A separate interface for asynchronous requests can be defined in a separate PSR +once a Promise PSR is accepted. The method signature for asynchronous requests +MUST be different from the method signature for synchronous requests because +the return type of asynchronous calls will be a Promise. Thus this PSR is forwards +compatible, and clients will be able to implement one or both interfaces based +on the features they wish to expose. + +## Approaches + +### Default behavior + +The intention of this PSR is to provide library developers with HTTP clients that +have a well defined behaviour. A library should be able to use any compliant client +without special code to handle client implementation details (Liskov substitution +principle). The PSR does not try to restrict nor define how to configure HTTP clients. + +An alternative approach would be to pass configuration to the client. That approach +would have a few drawbacks: + +* Configuration must be defined by the PSR. +* All clients must support the defined configuration. +* If no configuration is passed to the client, the behavior is unpredictable. + +#### Naming rationale + +The main interface behaviour is defined by the method `sendRequest(RequestInterface $request): ResponseInterface`. +While the shorter method name `send()` has been proposed, this was already used by existing and very common HTTP clients like Guzzle. As such, if they are to adopt this standard, they may need to break backwards compatibility in order to implement the specification. By defining `sendRequest()` instead, we ensure they can adopt without any immediate BC breaks. + +### Exception Model + +The domain exceptions `NetworkExceptionInterface` and `RequestExceptionInterface` define +a contract very similar to each other. The chosen approach is to not let them extend each other +because inheritance does not make sense in the domain model. A `RequestExceptionInterface` is simply not a +`NetworkExceptionInterface`. + +Allowing exceptions to extend a `RequestAwareException` and/or `ResponseAwareException` interface +has been discussed but that is a convenience shortcut that one should not take. One should rather +catch the specific exceptions and handle them accordingly. + +One could be more granular when defining exceptions. For example, `TimeOutException` and `HostNotFoundException` +could be subtypes of `NetworkExceptionInterface`. The chosen approach is not to define such subtypes because +the exception handling in a consuming library would in most cases not be different between those exceptions. + +#### Throwing exceptions for 4xx and 5xx responses + +The initial idea was to allow the client to be configured to throw exceptions for responses +with HTTP status 4xx and 5xx. That approach is not desired because consuming libraries would +have to check for 4xx and 5xx responses twice: first, by verifying the status code on the response, +and second by catching potential exceptions. + +To make the specification more predictable, it was decided that HTTP clients never will throw +exceptions for 4xx and 5xx responses. + +## Middleware and wrapping a client + +The specification does not put any limitations on middleware or classes that want +to wrap/decorate an HTTP client. If the decorating class also implements `ClientInterface` +then it must also follow the specification. + +It is temping to allow configuration or add middleware to an HTTP client so it could i.e. +follow redirects or throw exceptions. If that is a decision from an application developer, +they have specifically said they want to break the specification. That is an issue (or feature) +the application developer should handle. Third party libraries MUST NOT assume that +a HTTP client breaks the specification. + +## Background + +The HTTP client PSR has been inspired and created by the [php-http team](https://github.com/orgs/php-http/people). +Back in 2015, they created HTTPlug as a common interface for HTTP clients. They wanted an +abstraction that third party libraries could use so as not to rely on a specific HTTP client +implementation. A stable version was tagged in January 2016, and the project has been +widely adopted since then. With over 3 million downloads in the two years +following the initial stable version, it was time to convert this "de-facto" +standard into a formal specification. + +## People + +### 5.1 Editor + +* Tobias Nyholm + +### 5.2 Sponsors + +* Sara Golemon + +### 5.3 Workgroup + +* Simon Asika (Windwalker) +* David Buchmann (HTTPlug) +* David De Boer (HTTPlug) +* Sara Golemon (Sponsor) +* Jeremy Lindblom (Guzzle) +* Christian Lück (Buzz react) +* Tobias Nyholm (Editor) +* Matthew Weier O'Phinney (Zend) +* Mark Sagi-Kazar (Guzzle) +* Joel Wurtz (HTTPlug) + +## Votes + +* [Entrance vote](https://groups.google.com/d/topic/php-fig/MJGYRXfUJGk/discussion) +* [Review Period Initiation](https://groups.google.com/d/topic/php-fig/dV9zIaOooZ4/discussion) +* [Acceptance](https://groups.google.com/d/topic/php-fig/rScdiW38nLM/discussion) + +## Proposed implementations + +Below are the two implementations provided by the working group to pass the review period: + + * HTTPlug has prepared a 2.0 to make sure it is supporting the new PSR. + They are just waiting for the PSR to be released: https://github.com/php-http/httplug/tree/2.x + * Buzz has been adapting to every version of the PSR and has their 0.17.3 release with the latest + version of psr/http-client: https://github.com/kriswallsmith/Buzz diff --git a/_docs/psr/PSR-18-http-client.md b/_docs/psr/PSR-18-http-client.md new file mode 100644 index 0000000..af37997 --- /dev/null +++ b/_docs/psr/PSR-18-http-client.md @@ -0,0 +1,161 @@ +HTTP Client +=========== + +This document describes a common interface for sending HTTP requests and receiving HTTP responses. + +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 [RFC 2119](http://tools.ietf.org/html/rfc2119). + +## Goal + +The goal of this PSR is to allow developers to create libraries decoupled from HTTP client +implementations. This will make libraries more reusable as it reduces the number of +dependencies and lowers the likelihood of version conflicts. + +A second goal is that HTTP clients can be replaced as per the +[Liskov substitution principle][Liskov]. This means that all clients MUST behave in the +same way when sending a request. + +## Definitions + +* **Client** - A Client is a library that implements this specification for the purposes of +sending PSR-7-compatible HTTP Request messages and returning a PSR-7-compatible HTTP Response message to a Calling library. +* **Calling Library** - A Calling Library is any code that makes use of a Client. It does not implement +this specification's interfaces but consumes an object that implements them (a Client). + +## Client + +A Client is an object implementing `ClientInterface`. + +A Client MAY: + +* Choose to send an altered HTTP request from the one it was provided. For example, it could +compress an outgoing message body. +* Choose to alter a received HTTP response before returning it to the calling library. For example, it could +decompress an incoming message body. + +If a Client chooses to alter either the HTTP request or HTTP response, it MUST ensure that the +object remains internally consistent. For example, if a Client chooses to decompress the message +body then it MUST also remove the `Content-Encoding` header and adjust the `Content-Length` header. + +Note that as a result, since [PSR-7 objects are immutable](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-7-http-message-meta.md#why-value-objects), +the Calling Library MUST NOT assume that the object passed to `ClientInterface::sendRequest()` will be the same PHP object +that is actually sent. For example, the Request object that is returned by an exception MAY be a different object than +the one passed to `sendRequest()`, so comparison by reference (===) is not possible. + +A Client MUST: + +* Reassemble a multi-step HTTP 1xx response itself so that what is returned to the Calling Library is a valid HTTP response +of status code 200 or higher. + +## Error handling + +A Client MUST NOT treat a well-formed HTTP request or HTTP response as an error condition. For example, response +status codes in the 400 and 500 range MUST NOT cause an exception and MUST be returned to the Calling Library as normal. + +A Client MUST throw an instance of `Psr\Http\Client\ClientExceptionInterface` if and only if it is unable to send +the HTTP request at all or if the HTTP response could not be parsed into a PSR-7 response object. + +If a request cannot be sent because the request message is not a well-formed HTTP request or is missing some critical +piece of information (such as a Host or Method), the Client MUST throw an instance of `Psr\Http\Client\RequestExceptionInterface`. + +If the request cannot be sent due to a network failure of any kind, including a timeout, the Client MUST throw an +instance of `Psr\Http\Client\NetworkExceptionInterface`. + +Clients MAY throw more specific exceptions than those defined here (a `TimeOutException` or `HostNotFoundException` for +example), provided they implement the appropriate interface defined above. + +## Interfaces + +### ClientInterface + +```php +namespace Psr\Http\Client; + +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; + +interface ClientInterface +{ + /** + * Sends a PSR-7 request and returns a PSR-7 response. + * + * @param RequestInterface $request + * + * @return ResponseInterface + * + * @throws \Psr\Http\Client\ClientExceptionInterface If an error happens while processing the request. + */ + public function sendRequest(RequestInterface $request): ResponseInterface; +} +``` + +### ClientExceptionInterface + +```php +namespace Psr\Http\Client; + +/** + * Every HTTP client related exception MUST implement this interface. + */ +interface ClientExceptionInterface extends \Throwable +{ +} +``` + +### RequestExceptionInterface + +```php +namespace Psr\Http\Client; + +use Psr\Http\Message\RequestInterface; + +/** + * Exception for when a request failed. + * + * Examples: + * - Request is invalid (e.g. method is missing) + * - Runtime request errors (e.g. the body stream is not seekable) + */ +interface RequestExceptionInterface extends ClientExceptionInterface +{ + /** + * Returns the request. + * + * The request object MAY be a different object from the one passed to ClientInterface::sendRequest() + * + * @return RequestInterface + */ + public function getRequest(): RequestInterface; +} +``` + +### NetworkExceptionInterface + +```php +namespace Psr\Http\Client; + +use Psr\Http\Message\RequestInterface; + +/** + * Thrown when the request cannot be completed because of network issues. + * + * There is no response object as this exception is thrown when no response has been received. + * + * Example: the target host name can not be resolved or the connection failed. + */ +interface NetworkExceptionInterface extends ClientExceptionInterface +{ + /** + * Returns the request. + * + * The request object MAY be a different object from the one passed to ClientInterface::sendRequest() + * + * @return RequestInterface + */ + public function getRequest(): RequestInterface; +} +``` + +[Liskov]: https://en.wikipedia.org/wiki/Liskov_substitution_principle diff --git a/_docs/psr/PSR-2-coding-style-guide-meta.md b/_docs/psr/PSR-2-coding-style-guide-meta.md new file mode 100644 index 0000000..bd9e3ce --- /dev/null +++ b/_docs/psr/PSR-2-coding-style-guide-meta.md @@ -0,0 +1,38 @@ +## 1. Summary + +The intent of this guide is to reduce cognitive friction when scanning code from different authors. It does so +by enumerating a shared set of rules and expectations about how to format PHP code. + +The style rules herein are derived from commonalities among the various member projects. When various authors +collaborate across multiple projects, it helps to have one set of guidelines to be used among all those +projects. Thus, the benefit of this guide is not in the rules themselves, but in the sharing of those rules. + +## 2. Votes + +- **Acceptance Vote:** [ML](https://groups.google.com/d/msg/php-fig/c-QVvnZdMQ0/TdDMdzKFpdIJ) + +## 3. Errata + +### 3.1 - Multi-line Arguments (09/08/2013) + +Using one or more multi-line arguments (i.e: arrays or anonymous functions) does not constitute +splitting the argument list itself, therefore Section 4.6 is not automatically enforced. Arrays and anonymous +functions are able to span multiple lines. + +The following examples are perfectly valid in PSR-2: + +~~~php +get('/hello/{name}', function ($name) use ($app) { + return 'Hello '.$app->escape($name); +}); +~~~ + +### 3.2 - Extending Multiple Interfaces (10/17/2013) + +When extending multiple interfaces, the list of `extends` should be treated the same as a list +of `implements`, as declared in Section 4.1. diff --git a/_docs/psr/PSR-2-coding-style-guide.md b/_docs/psr/PSR-2-coding-style-guide.md index 4eeade7..2079afe 100644 --- a/_docs/psr/PSR-2-coding-style-guide.md +++ b/_docs/psr/PSR-2-coding-style-guide.md @@ -1,18 +1,4 @@ ---- -title: PRS-2 -category: PSRs -order: 2 ---- - -| Informações Adicionais | -| -----------------------------------------| -| [Meta Document][Meta Document] | -| [Coding Style Guide][Coding Style Guide] | - -[Meta Document]: #Meta Document -[Coding Style Guide]: #Coding Style Guide - -

Coding Style Guide

+#Guia de Estilo de Codificação This guide extends and expands on [PSR-1], the basic coding standard. @@ -797,46 +783,4 @@ A summary of what line the opening braces go on for classes, methods, and contro next/next/same: 11 next/same/same: 1 same/same/same: 6 - - - -

PSR-2 Meta Document

- -## 1. Summary - -The intent of this guide is to reduce cognitive friction when scanning code from different authors. It does so -by enumerating a shared set of rules and expectations about how to format PHP code. - -The style rules herein are derived from commonalities among the various member projects. When various authors -collaborate across multiple projects, it helps to have one set of guidelines to be used among all those -projects. Thus, the benefit of this guide is not in the rules themselves, but in the sharing of those rules. - -## 2. Votes - -- **Acceptance Vote:** [ML](https://groups.google.com/d/msg/php-fig/c-QVvnZdMQ0/TdDMdzKFpdIJ) - -## 3. Errata - -### 3.1 - Multi-line Arguments (09/08/2013) - -Using one or more multi-line arguments (i.e: arrays or anonymous functions) does not constitute -splitting the argument list itself, therefore Section 4.6 is not automatically enforced. Arrays and anonymous -functions are able to span multiple lines. - -The following examples are perfectly valid in PSR-2: - -~~~php -get('/hello/{name}', function ($name) use ($app) { - return 'Hello '.$app->escape($name); -}); -~~~ - -### 3.2 - Extending Multiple Interfaces (10/17/2013) - -When extending multiple interfaces, the list of `extends` should be treated the same as a list -of `implements`, as declared in Section 4.1. + \ No newline at end of file diff --git a/_docs/psr/PSR-3-logger-interface.md b/_docs/psr/PSR-3-logger-interface.md index 34d30ea..1124e9f 100644 --- a/_docs/psr/PSR-3-logger-interface.md +++ b/_docs/psr/PSR-3-logger-interface.md @@ -1,9 +1,3 @@ ---- -title: PRS-3 -category: PSRs -order: 3 ---- - Logger Interface ================ @@ -153,7 +147,7 @@ and a test suite to verify your implementation are provided as part of the namespace Psr\Log; /** - * Describes a logger instance + * Describes a logger instance. * * The message MUST be a string or object implementing __toString(). * @@ -272,12 +266,12 @@ interface LoggerInterface namespace Psr\Log; /** - * Describes a logger-aware instance + * Describes a logger-aware instance. */ interface LoggerAwareInterface { /** - * Sets a logger instance on the object + * Sets a logger instance on the object. * * @param LoggerInterface $logger * @return void @@ -294,7 +288,7 @@ interface LoggerAwareInterface namespace Psr\Log; /** - * Describes log levels + * Describes log levels. */ class LogLevel { diff --git a/_docs/psr/PSR-4-autoloader-examples.md b/_docs/psr/PSR-4-autoloader-examples.md new file mode 100644 index 0000000..3481846 --- /dev/null +++ b/_docs/psr/PSR-4-autoloader-examples.md @@ -0,0 +1,350 @@ +Example Implementations of PSR-4 +================================ + +The following examples illustrate PSR-4 compliant code: + +Closure Example +--------------- + +~~~php +register(); + * + * // register the base directories for the namespace prefix + * $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src'); + * $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests'); + * + * The following line would cause the autoloader to attempt to load the + * \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php: + * + * prefixes[$prefix]) === false) { + $this->prefixes[$prefix] = array(); + } + + // retain the base directory for the namespace prefix + if ($prepend) { + array_unshift($this->prefixes[$prefix], $base_dir); + } else { + array_push($this->prefixes[$prefix], $base_dir); + } + } + + /** + * Loads the class file for a given class name. + * + * @param string $class The fully-qualified class name. + * @return mixed The mapped file name on success, or boolean false on + * failure. + */ + public function loadClass($class) + { + // the current namespace prefix + $prefix = $class; + + // work backwards through the namespace names of the fully-qualified + // class name to find a mapped file name + while (false !== $pos = strrpos($prefix, '\\')) { + + // retain the trailing namespace separator in the prefix + $prefix = substr($class, 0, $pos + 1); + + // the rest is the relative class name + $relative_class = substr($class, $pos + 1); + + // try to load a mapped file for the prefix and relative class + $mapped_file = $this->loadMappedFile($prefix, $relative_class); + if ($mapped_file) { + return $mapped_file; + } + + // remove the trailing namespace separator for the next iteration + // of strrpos() + $prefix = rtrim($prefix, '\\'); + } + + // never found a mapped file + return false; + } + + /** + * Load the mapped file for a namespace prefix and relative class. + * + * @param string $prefix The namespace prefix. + * @param string $relative_class The relative class name. + * @return mixed Boolean false if no mapped file can be loaded, or the + * name of the mapped file that was loaded. + */ + protected function loadMappedFile($prefix, $relative_class) + { + // are there any base directories for this namespace prefix? + if (isset($this->prefixes[$prefix]) === false) { + return false; + } + + // look through base directories for this namespace prefix + foreach ($this->prefixes[$prefix] as $base_dir) { + + // replace the namespace prefix with the base directory, + // replace namespace separators with directory separators + // in the relative class name, append with .php + $file = $base_dir + . str_replace('\\', '/', $relative_class) + . '.php'; + + // if the mapped file exists, require it + if ($this->requireFile($file)) { + // yes, we're done + return $file; + } + } + + // never found it + return false; + } + + /** + * If a file exists, require it from the file system. + * + * @param string $file The file to require. + * @return bool True if the file exists, false if not. + */ + protected function requireFile($file) + { + if (file_exists($file)) { + require $file; + return true; + } + return false; + } +} +~~~ + +### Unit Tests + +The following example is one way of unit testing the above class loader: + +~~~php +files = $files; + } + + protected function requireFile($file) + { + return in_array($file, $this->files); + } +} + +class Psr4AutoloaderClassTest extends \PHPUnit_Framework_TestCase +{ + protected $loader; + + protected function setUp() + { + $this->loader = new MockPsr4AutoloaderClass; + + $this->loader->setFiles(array( + '/vendor/foo.bar/src/ClassName.php', + '/vendor/foo.bar/src/DoomClassName.php', + '/vendor/foo.bar/tests/ClassNameTest.php', + '/vendor/foo.bardoom/src/ClassName.php', + '/vendor/foo.bar.baz.dib/src/ClassName.php', + '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php', + )); + + $this->loader->addNamespace( + 'Foo\Bar', + '/vendor/foo.bar/src' + ); + + $this->loader->addNamespace( + 'Foo\Bar', + '/vendor/foo.bar/tests' + ); + + $this->loader->addNamespace( + 'Foo\BarDoom', + '/vendor/foo.bardoom/src' + ); + + $this->loader->addNamespace( + 'Foo\Bar\Baz\Dib', + '/vendor/foo.bar.baz.dib/src' + ); + + $this->loader->addNamespace( + 'Foo\Bar\Baz\Dib\Zim\Gir', + '/vendor/foo.bar.baz.dib.zim.gir/src' + ); + } + + public function testExistingFile() + { + $actual = $this->loader->loadClass('Foo\Bar\ClassName'); + $expect = '/vendor/foo.bar/src/ClassName.php'; + $this->assertSame($expect, $actual); + + $actual = $this->loader->loadClass('Foo\Bar\ClassNameTest'); + $expect = '/vendor/foo.bar/tests/ClassNameTest.php'; + $this->assertSame($expect, $actual); + } + + public function testMissingFile() + { + $actual = $this->loader->loadClass('No_Vendor\No_Package\NoClass'); + $this->assertFalse($actual); + } + + public function testDeepFile() + { + $actual = $this->loader->loadClass('Foo\Bar\Baz\Dib\Zim\Gir\ClassName'); + $expect = '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php'; + $this->assertSame($expect, $actual); + } + + public function testConfusion() + { + $actual = $this->loader->loadClass('Foo\Bar\DoomClassName'); + $expect = '/vendor/foo.bar/src/DoomClassName.php'; + $this->assertSame($expect, $actual); + + $actual = $this->loader->loadClass('Foo\BarDoom\ClassName'); + $expect = '/vendor/foo.bardoom/src/ClassName.php'; + $this->assertSame($expect, $actual); + } +} +~~~ diff --git a/_docs/psr/PSR-4-autoloader-meta.md b/_docs/psr/PSR-4-autoloader-meta.md new file mode 100644 index 0000000..b01495d --- /dev/null +++ b/_docs/psr/PSR-4-autoloader-meta.md @@ -0,0 +1,276 @@ +# PSR-4 Meta Document + +## 1. Summary + +The purpose is to specify the rules for an interoperable PHP autoloader that +maps namespaces to file system paths, and that can co-exist with any other SPL +registered autoloader. This would be an addition to, not a replacement for, +PSR-0. + +## 2. Why Bother? + +### History of PSR-0 + +The PSR-0 class naming and autoloading standard rose out of the broad +acceptance of the Horde/PEAR convention under the constraints of PHP 5.2 and +previous. With that convention, the tendency was to put all PHP source classes +in a single main directory, using underscores in the class name to indicate +pseudo-namespaces, like so: + + /path/to/src/ + VendorFoo/ + Bar/ + Baz.php # VendorFoo_Bar_Baz + VendorDib/ + Zim/ + Gir.php # Vendor_Dib_Zim_Gir + +With the release of PHP 5.3 and the availability of namespaces proper, PSR-0 +was introduced to allow both the old Horde/PEAR underscore mode *and* the use +of the new namespace notation. Underscores were still allowed in the class +name to ease the transition from the older namespace naming to the newer naming, +and thereby to encourage wider adoption. + + /path/to/src/ + VendorFoo/ + Bar/ + Baz.php # VendorFoo_Bar_Baz + VendorDib/ + Zim/ + Gir.php # VendorDib_Zim_Gir + Irk_Operation/ + Impending_Doom/ + V1.php + V2.php # Irk_Operation\Impending_Doom\V2 + +This structure is informed very much by the fact that the PEAR installer moved +source files from PEAR packages into a single central directory. + +### Along Comes Composer + +With Composer, package sources are no longer copied to a single global +location. They are used from their installed location and are not moved +around. This means that with Composer there is no "single main directory" for +PHP sources as with PEAR. Instead, there are multiple directories; each +package is in a separate directory for each project. + +To meet the requirements of PSR-0, this leads to Composer packages looking +like this: + + vendor/ + vendor_name/ + package_name/ + src/ + Vendor_Name/ + Package_Name/ + ClassName.php # Vendor_Name\Package_Name\ClassName + tests/ + Vendor_Name/ + Package_Name/ + ClassNameTest.php # Vendor_Name\Package_Name\ClassNameTest + +The "src" and "tests" directories have to include vendor and package directory +names. This is an artifact of PSR-0 compliance. + +Many find this structure to be deeper and more repetitive than necessary. This +proposal suggests that an additional or superseding PSR would be useful so +that we can have packages that look more like the following: + + vendor/ + vendor_name/ + package_name/ + src/ + ClassName.php # Vendor_Name\Package_Name\ClassName + tests/ + ClassNameTest.php # Vendor_Name\Package_Name\ClassNameTest + +This would require an implementation of what was initially called +"package-oriented autoloading" (as vs the traditional "direct class-to-file +autoloading"). + +### Package-Oriented Autoloading + +It's difficult to implement package-oriented autoloading via an extension or +amendment to PSR-0, because PSR-0 does not allow for an intercessory path +between any portions of the class name. This means the implementation of a +package-oriented autoloader would be more complicated than PSR-0. However, it +would allow for cleaner packages. + +Initially, the following rules were suggested: + +1. Implementors MUST use at least two namespace levels: a vendor name, and +package name within that vendor. (This top-level two-name combination is +hereinafter referred to as the vendor-package name or the vendor-package +namespace.) + +2. Implementors MUST allow a path infix between the vendor-package namespace +and the remainder of the fully qualified class name. + +3. The vendor-package namespace MAY map to any directory. The remaining +portion of the fully-qualified class name MUST map the namespace names to +identically-named directories, and MUST map the class name to an +identically-named file ending in .php. + +Note that this means the end of underscore-as-directory-separator in the class +name. One might think underscores should be honored as they are under +PSR-0, but seeing as their presence in that document is in reference to +transitioning away from PHP 5.2 and previous pseudo-namespacing, it is +acceptable to remove them here as well. + +## 3. Scope + +### 3.1 Goals + +- Retain the PSR-0 rule that implementors MUST use at least two namespace + levels: a vendor name, and package name within that vendor. + +- Allow a path infix between the vendor-package namespace and the remainder of + the fully qualified class name. + +- Allow the vendor-package namespace MAY map to any directory, perhaps + multiple directories. + +- End the honoring of underscores in class names as directory separators + +### 3.2 Non-Goals + +- Provide a general transformation algorithm for non-class resources + +## 4. Approaches + +### 4.1 Chosen Approach + +This approach retains key characteristics of PSR-0 while eliminating the +deeper directory structures it requires. In addition, it specifies certain +additional rules that make implementations explicitly more interoperable. + +Although not related to directory mapping, the final draft also specifies how +autoloaders should handle errors. Specifically, it forbids throwing exceptions +or raising errors. The reason is two-fold. + +1. Autoloaders in PHP are explicitly designed to be stackable so that if one +autoloader cannot load a class another has a chance to do so. Having an autoloader +trigger a breaking error condition violates that compatibility. + +2. `class_exists()` and `interface_exists()` allow "not found, even after trying to +autoload" as a legitimate, normal use case. An autoloader that throws exceptions +renders `class_exists()` unusable, which is entirely unacceptable from an interoperability +standpoint. Autoloaders that wish to provide additional debugging information +in a class-not-found case should do so via logging instead, either to a PSR-3 +compatible logger or otherwise. + +Pros: + +- Shallower directory structures + +- More flexible file locations + +- Stops underscore in class name from being honored as directory separator + +- Makes implementations more explicitly interoperable + +Cons: + +- It is no longer possible, as under PSR-0, to merely examine a class name to + determine where it is in the file system (the "class-to-file" convention + inherited from Horde/PEAR). + +### 4.2 Alternative: Stay With PSR-0 Only + +Staying with PSR-0 only, although reasonable, does leave us with relatively +deeper directory structures. + +Pros: + +- No need to change anyone's habits or implementations + +Cons: + +- Leaves us with deeper directory structures + +- Leaves us with underscores in the class name being honored as directory + separators + +### 4.3 Alternative: Split Up Autoloading And Transformation + +Beau Simensen and others suggested that the transformation algorithm might be +split out from the autoloading proposal so that the transformation rules +could be referenced by other proposals. After doing the work to separate them, +followed by a poll and some discussion, the combined version (i.e., +transformation rules embedded in the autoloader proposal) was revealed as the +preference. + +Pros: + +- Transformation rules could be referenced separately by other proposals + +Cons: + +- Not in line with the wishes of poll respondents and some collaborators + +### 4.4 Alternative: Use More Imperative And Narrative Language + +After the second vote was pulled by a Sponsor after hearing from multiple +1 +voters that they supported the idea but did not agree with (or understand) the +wording of the proposal, there was a period during which the voted-on proposal +was expanded with greater narrative and somewhat more imperative language. This +approach was decried by a vocal minority of participants. After some time, Beau +Simensen started an experimental revision with an eye to PSR-0; the Editor and +Sponsors favored this more terse approach and shepherded the version now under +consideration, written by Paul M. Jones and contributed to by many. + +### Compatibility Note with PHP 5.3.2 and below + +PHP versions before 5.3.3 do not strip the leading namespace separator, so +the responsibility to look out for this falls on the implementation. Failing +to strip the leading namespace separator could lead to unexpected behavior. + +## 5. People + +### 5.1 Editor + +- Paul M. Jones, Solar/Aura + +### 5.2 Sponsors + +- Phil Sturgeon, PyroCMS (Coordinator) +- Larry Garfield, Drupal + +### 5.3 Contributors + +- Andreas Hennings +- Bernhard Schussek +- Beau Simensen +- Donald Gilbert +- Mike van Riel +- Paul Dragoonis +- Too many others to name and count + +## 6. Votes + +- **Entrance Vote:** + +- **Acceptance Vote:** + + - 1st attempt: , + presented prior to new workflow; aborted due to accidental proposal modification + + - 2nd attempt: , + cancelled at the discretion of the sponsor + + - 3rd attempt: TBD + +## 7. Relevant Links + +- [Autoloader, round 4](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/lpmJcmkNYjM) +- [POLL: Autoloader: Split or Combined?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/fGwA6XHlYhI) +- [PSR-X autoloader spec: Loopholes, ambiguities](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/kUbzJAbHxmg) +- [Autoloader: Combine Proposals?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/422dFBGs1Yc) +- [Package-Oriented Autoloader, Round 2](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Y4xc71Q3YEQ) +- [Autoloader: looking again at namespace](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/bnoiTxE8L28) +- [DISCUSSION: Package-Oriented Autoloader - vote against](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/SJTL1ec46II) +- [VOTE: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Ua46E344_Ls) +- [Proposal: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/qT7mEy0RIuI) +- [Towards a Package Oriented Autoloader](https://groups.google.com/forum/#!searchin/php-fig/package$20oriented$20autoloader/php-fig/JdR-g8ZxKa8/jJr80ard-ekJ) +- [List of Alternative PSR-4 Proposals](https://groups.google.com/forum/#!topic/php-fig/oXr-2TU1lQY) +- [Summary of [post-Acceptance Vote pull] PSR-4 discussions](https://groups.google.com/forum/#!searchin/php-fig/psr-4$20summary/php-fig/bSTwUX58NhE/YPcFgBjwvpEJ) diff --git a/_docs/psr/PSR-4-autoloader.md b/_docs/psr/PSR-4-autoloader.md index a11a0b5..6514c23 100644 --- a/_docs/psr/PSR-4-autoloader.md +++ b/_docs/psr/PSR-4-autoloader.md @@ -1,22 +1,4 @@ ---- -title: PRS-4 -category: PSRs -order: 4 ---- - -| Informações Adicionais | -| ---------------------------------------------------| -| [Autoloader][Autoloader] | -| [Meta Document][Meta Document] | -| [Example Implementations][Example Implementations] | - -[Autoloader]: #Autoloader -[Meta Document]: #Meta Document -[Example Implementations]: #Example Implementations - - -

Autoloader

- +# Autoloader The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be @@ -91,633 +73,3 @@ as part of the specification and MAY change at any time. [autoloading]: http://php.net/autoload [PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md [examples file]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md - - -

PSR-4 Meta Document

- -## 1. Summary - -The purpose is to specify the rules for an interoperable PHP autoloader that -maps namespaces to file system paths, and that can co-exist with any other SPL -registered autoloader. This would be an addition to, not a replacement for, -PSR-0. - -## 2. Why Bother? - -### History of PSR-0 - -The PSR-0 class naming and autoloading standard rose out of the broad -acceptance of the Horde/PEAR convention under the constraints of PHP 5.2 and -previous. With that convention, the tendency was to put all PHP source classes -in a single main directory, using underscores in the class name to indicate -pseudo-namespaces, like so: - - /path/to/src/ - VendorFoo/ - Bar/ - Baz.php # VendorFoo_Bar_Baz - VendorDib/ - Zim/ - Gir.php # Vendor_Dib_Zim_Gir - -With the release of PHP 5.3 and the availability of namespaces proper, PSR-0 -was introduced to allow both the old Horde/PEAR underscore mode *and* the use -of the new namespace notation. Underscores were still allowed in the class -name to ease the transition from the older namespace naming to the newer naming, -and thereby to encourage wider adoption. - - /path/to/src/ - VendorFoo/ - Bar/ - Baz.php # VendorFoo_Bar_Baz - VendorDib/ - Zim/ - Gir.php # VendorDib_Zim_Gir - Irk_Operation/ - Impending_Doom/ - V1.php - V2.php # Irk_Operation\Impending_Doom\V2 - -This structure is informed very much by the fact that the PEAR installer moved -source files from PEAR packages into a single central directory. - -### Along Comes Composer - -With Composer, package sources are no longer copied to a single global -location. They are used from their installed location and are not moved -around. This means that with Composer there is no "single main directory" for -PHP sources as with PEAR. Instead, there are multiple directories; each -package is in a separate directory for each project. - -To meet the requirements of PSR-0, this leads to Composer packages looking -like this: - - vendor/ - vendor_name/ - package_name/ - src/ - Vendor_Name/ - Package_Name/ - ClassName.php # Vendor_Name\Package_Name\ClassName - tests/ - Vendor_Name/ - Package_Name/ - ClassNameTest.php # Vendor_Name\Package_Name\ClassNameTest - -The "src" and "tests" directories have to include vendor and package directory -names. This is an artifact of PSR-0 compliance. - -Many find this structure to be deeper and more repetitive than necessary. This -proposal suggests that an additional or superseding PSR would be useful so -that we can have packages that look more like the following: - - vendor/ - vendor_name/ - package_name/ - src/ - ClassName.php # Vendor_Name\Package_Name\ClassName - tests/ - ClassNameTest.php # Vendor_Name\Package_Name\ClassNameTest - -This would require an implementation of what was initially called -"package-oriented autoloading" (as vs the traditional "direct class-to-file -autoloading"). - -### Package-Oriented Autoloading - -It's difficult to implement package-oriented autoloading via an extension or -amendment to PSR-0, because PSR-0 does not allow for an intercessory path -between any portions of the class name. This means the implementation of a -package-oriented autoloader would be more complicated than PSR-0. However, it -would allow for cleaner packages. - -Initially, the following rules were suggested: - -1. Implementors MUST use at least two namespace levels: a vendor name, and -package name within that vendor. (This top-level two-name combination is -hereinafter referred to as the vendor-package name or the vendor-package -namespace.) - -2. Implementors MUST allow a path infix between the vendor-package namespace -and the remainder of the fully qualified class name. - -3. The vendor-package namespace MAY map to any directory. The remaining -portion of the fully-qualified class name MUST map the namespace names to -identically-named directories, and MUST map the class name to an -identically-named file ending in .php. - -Note that this means the end of underscore-as-directory-separator in the class -name. One might think underscores should be honored as they are under -PSR-0, but seeing as their presence in that document is in reference to -transitioning away from PHP 5.2 and previous pseudo-namespacing, it is -acceptable to remove them here as well. - -## 3. Scope - -### 3.1 Goals - -- Retain the PSR-0 rule that implementors MUST use at least two namespace - levels: a vendor name, and package name within that vendor. - -- Allow a path infix between the vendor-package namespace and the remainder of - the fully qualified class name. - -- Allow the vendor-package namespace MAY map to any directory, perhaps - multiple directories. - -- End the honoring of underscores in class names as directory separators - -### 3.2 Non-Goals - -- Provide a general transformation algorithm for non-class resources - -## 4. Approaches - -### 4.1 Chosen Approach - -This approach retains key characteristics of PSR-0 while eliminating the -deeper directory structures it requires. In addition, it specifies certain -additional rules that make implementations explicitly more interoperable. - -Although not related to directory mapping, the final draft also specifies how -autoloaders should handle errors. Specifically, it forbids throwing exceptions -or raising errors. The reason is two-fold. - -1. Autoloaders in PHP are explicitly designed to be stackable so that if one -autoloader cannot load a class another has a chance to do so. Having an autoloader -trigger a breaking error condition violates that compatibility. - -2. `class_exists()` and `interface_exists()` allow "not found, even after trying to -autoload" as a legitimate, normal use case. An autoloader that throws exceptions -renders `class_exists()` unusable, which is entirely unacceptable from an interoperability -standpoint. Autoloaders that wish to provide additional debugging information -in a class-not-found case should do so via logging instead, either to a PSR-3 -compatible logger or otherwise. - -Pros: - -- Shallower directory structures - -- More flexible file locations - -- Stops underscore in class name from being honored as directory separator - -- Makes implementations more explicitly interoperable - -Cons: - -- It is no longer possible, as under PSR-0, to merely examine a class name to - determine where it is in the file system (the "class-to-file" convention - inherited from Horde/PEAR). - -### 4.2 Alternative: Stay With PSR-0 Only - -Staying with PSR-0 only, although reasonable, does leave us with relatively -deeper directory structures. - -Pros: - -- No need to change anyone's habits or implementations - -Cons: - -- Leaves us with deeper directory structures - -- Leaves us with underscores in the class name being honored as directory - separators - -### 4.3 Alternative: Split Up Autoloading And Transformation - -Beau Simensen and others suggested that the transformation algorithm might be -split out from the autoloading proposal so that the transformation rules -could be referenced by other proposals. After doing the work to separate them, -followed by a poll and some discussion, the combined version (i.e., -transformation rules embedded in the autoloader proposal) was revealed as the -preference. - -Pros: - -- Transformation rules could be referenced separately by other proposals - -Cons: - -- Not in line with the wishes of poll respondents and some collaborators - -### 4.4 Alternative: Use More Imperative And Narrative Language - -After the second vote was pulled by a Sponsor after hearing from multiple +1 -voters that they supported the idea but did not agree with (or understand) the -wording of the proposal, there was a period during which the voted-on proposal -was expanded with greater narrative and somewhat more imperative language. This -approach was decried by a vocal minority of participants. After some time, Beau -Simensen started an experimental revision with an eye to PSR-0; the Editor and -Sponsors favored this more terse approach and shepherded the version now under -consideration, written by Paul M. Jones and contributed to by many. - -### Compatibility Note with PHP 5.3.2 and below - -PHP versions before 5.3.3 do not strip the leading namespace separator, so -the responsibility to look out for this falls on the implementation. Failing -to strip the leading namespace separator could lead to unexpected behavior. - -## 5. People - -### 5.1 Editor - -- Paul M. Jones, Solar/Aura - -### 5.2 Sponsors - -- Phil Sturgeon, PyroCMS (Coordinator) -- Larry Garfield, Drupal - -### 5.3 Contributors - -- Andreas Hennings -- Bernhard Schussek -- Beau Simensen -- Donald Gilbert -- Mike van Riel -- Paul Dragoonis -- Too many others to name and count - -## 6. Votes - -- **Entrance Vote:** - -- **Acceptance Vote:** - - - 1st attempt: , - presented prior to new workflow; aborted due to accidental proposal modification - - - 2nd attempt: , - cancelled at the discretion of the sponsor - - - 3rd attempt: TBD - -## 7. Relevant Links - -- [Autoloader, round 4](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/lpmJcmkNYjM) -- [POLL: Autoloader: Split or Combined?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/fGwA6XHlYhI) -- [PSR-X autoloader spec: Loopholes, ambiguities](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/kUbzJAbHxmg) -- [Autoloader: Combine Proposals?](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/422dFBGs1Yc) -- [Package-Oriented Autoloader, Round 2](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Y4xc71Q3YEQ) -- [Autoloader: looking again at namespace](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/bnoiTxE8L28) -- [DISCUSSION: Package-Oriented Autoloader - vote against](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/SJTL1ec46II) -- [VOTE: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/Ua46E344_Ls) -- [Proposal: Package-Oriented Autoloader](https://groups.google.com/forum/#!topicsearchin/php-fig/autoload/php-fig/qT7mEy0RIuI) -- [Towards a Package Oriented Autoloader](https://groups.google.com/forum/#!searchin/php-fig/package$20oriented$20autoloader/php-fig/JdR-g8ZxKa8/jJr80ard-ekJ) -- [List of Alternative PSR-4 Proposals](https://groups.google.com/forum/#!topic/php-fig/oXr-2TU1lQY) -- [Summary of [post-Acceptance Vote pull] PSR-4 discussions](https://groups.google.com/forum/#!searchin/php-fig/psr-4$20summary/php-fig/bSTwUX58NhE/YPcFgBjwvpEJ) - - - -

Example Implementations of PSR-4

- -The following examples illustrate PSR-4 compliant code: - -Closure Example ---------------- - -~~~php -register(); - * - * // register the base directories for the namespace prefix - * $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/src'); - * $loader->addNamespace('Foo\Bar', '/path/to/packages/foo-bar/tests'); - * - * The following line would cause the autoloader to attempt to load the - * \Foo\Bar\Qux\Quux class from /path/to/packages/foo-bar/src/Qux/Quux.php: - * - * prefixes[$prefix]) === false) { - $this->prefixes[$prefix] = array(); - } - - // retain the base directory for the namespace prefix - if ($prepend) { - array_unshift($this->prefixes[$prefix], $base_dir); - } else { - array_push($this->prefixes[$prefix], $base_dir); - } - } - - /** - * Loads the class file for a given class name. - * - * @param string $class The fully-qualified class name. - * @return mixed The mapped file name on success, or boolean false on - * failure. - */ - public function loadClass($class) - { - // the current namespace prefix - $prefix = $class; - - // work backwards through the namespace names of the fully-qualified - // class name to find a mapped file name - while (false !== $pos = strrpos($prefix, '\\')) { - - // retain the trailing namespace separator in the prefix - $prefix = substr($class, 0, $pos + 1); - - // the rest is the relative class name - $relative_class = substr($class, $pos + 1); - - // try to load a mapped file for the prefix and relative class - $mapped_file = $this->loadMappedFile($prefix, $relative_class); - if ($mapped_file) { - return $mapped_file; - } - - // remove the trailing namespace separator for the next iteration - // of strrpos() - $prefix = rtrim($prefix, '\\'); - } - - // never found a mapped file - return false; - } - - /** - * Load the mapped file for a namespace prefix and relative class. - * - * @param string $prefix The namespace prefix. - * @param string $relative_class The relative class name. - * @return mixed Boolean false if no mapped file can be loaded, or the - * name of the mapped file that was loaded. - */ - protected function loadMappedFile($prefix, $relative_class) - { - // are there any base directories for this namespace prefix? - if (isset($this->prefixes[$prefix]) === false) { - return false; - } - - // look through base directories for this namespace prefix - foreach ($this->prefixes[$prefix] as $base_dir) { - - // replace the namespace prefix with the base directory, - // replace namespace separators with directory separators - // in the relative class name, append with .php - $file = $base_dir - . str_replace('\\', '/', $relative_class) - . '.php'; - - // if the mapped file exists, require it - if ($this->requireFile($file)) { - // yes, we're done - return $file; - } - } - - // never found it - return false; - } - - /** - * If a file exists, require it from the file system. - * - * @param string $file The file to require. - * @return bool True if the file exists, false if not. - */ - protected function requireFile($file) - { - if (file_exists($file)) { - require $file; - return true; - } - return false; - } -} -~~~ - -### Unit Tests - -The following example is one way of unit testing the above class loader: - -~~~php -files = $files; - } - - protected function requireFile($file) - { - return in_array($file, $this->files); - } -} - -class Psr4AutoloaderClassTest extends \PHPUnit_Framework_TestCase -{ - protected $loader; - - protected function setUp() - { - $this->loader = new MockPsr4AutoloaderClass; - - $this->loader->setFiles(array( - '/vendor/foo.bar/src/ClassName.php', - '/vendor/foo.bar/src/DoomClassName.php', - '/vendor/foo.bar/tests/ClassNameTest.php', - '/vendor/foo.bardoom/src/ClassName.php', - '/vendor/foo.bar.baz.dib/src/ClassName.php', - '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php', - )); - - $this->loader->addNamespace( - 'Foo\Bar', - '/vendor/foo.bar/src' - ); - - $this->loader->addNamespace( - 'Foo\Bar', - '/vendor/foo.bar/tests' - ); - - $this->loader->addNamespace( - 'Foo\BarDoom', - '/vendor/foo.bardoom/src' - ); - - $this->loader->addNamespace( - 'Foo\Bar\Baz\Dib', - '/vendor/foo.bar.baz.dib/src' - ); - - $this->loader->addNamespace( - 'Foo\Bar\Baz\Dib\Zim\Gir', - '/vendor/foo.bar.baz.dib.zim.gir/src' - ); - } - - public function testExistingFile() - { - $actual = $this->loader->loadClass('Foo\Bar\ClassName'); - $expect = '/vendor/foo.bar/src/ClassName.php'; - $this->assertSame($expect, $actual); - - $actual = $this->loader->loadClass('Foo\Bar\ClassNameTest'); - $expect = '/vendor/foo.bar/tests/ClassNameTest.php'; - $this->assertSame($expect, $actual); - } - - public function testMissingFile() - { - $actual = $this->loader->loadClass('No_Vendor\No_Package\NoClass'); - $this->assertFalse($actual); - } - - public function testDeepFile() - { - $actual = $this->loader->loadClass('Foo\Bar\Baz\Dib\Zim\Gir\ClassName'); - $expect = '/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php'; - $this->assertSame($expect, $actual); - } - - public function testConfusion() - { - $actual = $this->loader->loadClass('Foo\Bar\DoomClassName'); - $expect = '/vendor/foo.bar/src/DoomClassName.php'; - $this->assertSame($expect, $actual); - - $actual = $this->loader->loadClass('Foo\BarDoom\ClassName'); - $expect = '/vendor/foo.bardoom/src/ClassName.php'; - $this->assertSame($expect, $actual); - } -} -~~~ diff --git a/_docs/psr/PSR-6-cache-meta.md b/_docs/psr/PSR-6-cache-meta.md new file mode 100644 index 0000000..220d1fb --- /dev/null +++ b/_docs/psr/PSR-6-cache-meta.md @@ -0,0 +1,336 @@ +# PSR-Cache Meta Document + +## 1. Summary + +Caching is a common way to improve the performance of any project, making +caching libraries one of the most common features of many frameworks and +libraries. This has lead to a situation where many libraries roll their own +caching libraries, with various levels of functionality. These differences are +causing developers to have to learn multiple systems which may or may not +provide the functionality they need. In addition, the developers of caching +libraries themselves face a choice between only supporting a limited number +of frameworks or creating a large number of adapter classes. + +## 2. Why Bother? + +A common interface for caching systems will solve these problems. Library and +framework developers can count on the caching systems working the way they're +expecting, while the developers of caching systems will only have to implement +a single set of interfaces rather than a whole assortment of adapters. + +Moreover, the implementation presented here is designed for future extensibility. +It allows a variety of internally-different but API-compatible implementations +and offers a clear path for future extension by later PSRs or by specific +implementers. + +Pros: +* A standard interface for caching allows free-standing libraries to support +caching of intermediary data without effort; they may simply (optionally) depend +on this standard interface and leverage it without being concerned about +implementation details. +* Commonly developed caching libraries shared by multiple projects, even if +they extend this interface, are likely to be more robust than a dozen separately +developed implementations. + +Cons: +* Any interface standardization runs the risk of stifling future innovation as +being "not the Way It's Done(tm)". However, we believe caching is a sufficiently +commoditized problem space that the extension capability offered here mitigates +any potential risk of stagnation. + +## 3. Scope + +### 3.1 Goals + +* A common interface for basic and intermediate-level caching needs. +* A clear mechanism for extending the specification to support advanced features, +both by future PSRs or by individual implementations. This mechanism must allow +for multiple independent extensions without collision. + +### 3.2 Non-Goals + +* Architectural compatibility with all existing cache implementations. +* Advanced caching features such as namespacing or tagging that are used by a +minority of users. + +## 4. Approaches + +### 4.1 Chosen Approach + +This specification adopts a "repository model" or "data mapper" model for caching +rather than the more traditional "expire-able key-value" model. The primary +reason is flexibility. A simple key/value model is much more difficult to extend. + +The model here mandates the use of a CacheItem object, which represents a cache +entry, and a Pool object, which is a given store of cached data. Items are +retrieved from the pool, interacted with, and returned to it. While a bit more +verbose at times it offers a good, robust, flexible approach to caching, +especially in cases where caching is more involved than simply saving and +retrieving a string. + +Most method names were chosen based on common practice and method names in a +survey of member projects and other popular non-member systems. + +Pros: + +* Flexible and extensible +* Allows a great deal of variation in implementation without violating the interface +* Does not implicitly expose object constructors as a pseudo-interface. + +Cons: + +* A bit more verbose than the naive approach + +Examples: + +Some common usage patterns are shown below. These are non-normative but should +demonstrate the application of some design decisions. + +~~~php +/** + * Gets a list of available widgets. + * + * In this case, we assume the widget list changes so rarely that we want + * the list cached forever until an explicit clear. + */ +function get_widget_list() +{ + $pool = get_cache_pool('widgets'); + $item = $pool->getItem('widget_list'); + if (!$item->isHit()) { + $value = compute_expensive_widget_list(); + $item->set($value); + $pool->save($item); + } + return $item->get(); +} +~~~ + +~~~php +/** + * Caches a list of available widgets. + * + * In this case, we assume a list of widgets has been computed and we want + * to cache it, regardless of what may already be cached. + */ +function save_widget_list($list) +{ + $pool = get_cache_pool('widgets'); + $item = $pool->getItem('widget_list'); + $item->set($list); + $pool->save($item); +} +~~~ + +~~~php +/** + * Clears the list of available widgets. + * + * In this case, we simply want to remove the widget list from the cache. We + * don't care if it was set or not; the post condition is simply "no longer set". + */ +function clear_widget_list() +{ + $pool = get_cache_pool('widgets'); + $pool->deleteItems(['widget_list']); +} +~~~ + +~~~php +/** + * Clears all widget information. + * + * In this case, we want to empty the entire widget pool. There may be other + * pools in the application that will be unaffected. + */ +function clear_widget_cache() +{ + $pool = get_cache_pool('widgets'); + $pool->clear(); +} +~~~ + +~~~php +/** + * Load widgets. + * + * We want to get back a list of widgets, of which some are cached and some + * are not. This of course assumes that loading from the cache is faster than + * whatever the non-cached loading mechanism is. + * + * In this case, we assume widgets may change frequently so we only allow them + * to be cached for an hour (3600 seconds). We also cache newly-loaded objects + * back to the pool en masse. + * + * Note that a real implementation would probably also want a multi-load + * operation for widgets, but that's irrelevant for this demonstration. + */ +function load_widgets(array $ids) +{ + $pool = get_cache_pool('widgets'); + $keys = array_map(function($id) { return 'widget.' . $id; }, $ids); + $items = $pool->getItems($keys); + + $widgets = array(); + foreach ($items as $key => $item) { + if ($item->isHit()) { + $value = $item->get(); + } else { + $value = expensive_widget_load($id); + $item->set($value); + $item->expiresAfter(3600); + $pool->saveDeferred($item, true); + } + $widget[$value->id()] = $value; + } + $pool->commit(); // If no items were deferred this is a no-op. + + return $widgets; +} +~~~ + +~~~php +/** + * This examples reflects functionality that is NOT included in this + * specification, but is shown as an example of how such functionality MIGHT + * be added by extending implementations. + */ + +interface TaggablePoolInterface extends Psr\Cache\CachePoolInterface +{ + /** + * Clears only those items from the pool that have the specified tag. + */ + clearByTag($tag); +} + +interface TaggableItemInterface extends Psr\Cache\CacheItemInterface +{ + public function setTags(array $tags); +} + +/** + * Caches a widget with tags. + */ +function set_widget(TaggablePoolInterface $pool, Widget $widget) +{ + $key = 'widget.' . $widget->id(); + $item = $pool->getItem($key); + + $item->setTags($widget->tags()); + $item->set($widget); + $pool->save($item); +} +~~~ + +### 4.2 Alternative: "Weak item" approach + +A variety of earlier drafts took a simpler "key value with expiration" approach, +also known as a "weak item" approach. In this model, the "Cache Item" object +was really just a dumb array-with-methods object. Users would instantiate it +directly, then pass it to a cache pool. While more familiar, that approach +effectively prevented any meaningful extension of the Cache Item. It effectively +made the Cache Item's constructor part of the implicit interface, and thus +severely curtailed extensibility or the ability to have the cache item be where +the intelligence lives. + +In a poll conducted in June 2013, most participants showed a clear preference for +the more robust if less conventional "Strong item" / repository approach, which +was adopted as the way forward. + +Pros: +* More traditional approach. + +Cons: +* Less extensible or flexible. + +### 4.3 Alternative: "Naked value" approach + +Some of the earliest discussions of the Cache spec suggested skipping the Cache +Item concept all together and just reading/writing raw values to be cached. +While simpler, it was pointed out that made it impossible to tell the difference +between a cache miss and whatever raw value was selected to represent a cache +miss. That is, if a cache lookup returned NULL it's impossible to tell if there +was no cached value or if NULL was the value that had been cached. (NULL is a +legitimate value to cache in many cases.) + +Most more robust caching implementations we reviewed -- in particular the Stash +caching library and the home-grown cache system used by Drupal -- use some sort +of structured object on `get` at least to avoid confusion between a miss and a +sentinel value. Based on that prior experience FIG decided that a naked value +on `get` was impossible. + +### 4.4 Alternative: ArrayAccess Pool + +There was a suggestion to make a Pool implement ArrayAccess, which would allow +for cache get/set operations to use array syntax. That was rejected due to +limited interest, limited flexibility of that approach (trivial get and set with +default control information is all that's possible), and because it's trivial +for a particular implementation to include as an add-on should it desire to +do so. + +## 5. People + +### 5.1 Editor + +* Larry Garfield + +### 5.2 Sponsors + +* Paul Dragoonis, PPI Framework (Coordinator) +* Robert Hafner, Stash + +## 6. Votes + +[Acceptance vote on the mailing list](https://groups.google.com/forum/#!msg/php-fig/dSw5IhpKJ1g/O9wpqizWAwAJ) + +## 7. Relevant Links + +_**Note:** Order descending chronologically._ + +* [Survey of existing cache implementations][1], by @dragoonis +* [Strong vs. Weak informal poll][2], by @Crell +* [Implementation details informal poll][3], by @Crell + +[1]: https://docs.google.com/spreadsheet/ccc?key=0Ak2JdGialLildEM2UjlOdnA4ekg3R1Bfeng5eGlZc1E#gid=0 +[2]: https://docs.google.com/spreadsheet/ccc?key=0AsMrMKNHL1uGdDdVd2llN1kxczZQejZaa3JHcXA3b0E#gid=0 +[3]: https://docs.google.com/spreadsheet/ccc?key=0AsMrMKNHL1uGdEE3SU8zclNtdTNobWxpZnFyR0llSXc#gid=1 + +## 8. Errata + +### 8.1 Handling of incorrect DateTime values in expiresAt() + +The `CacheItemInterface::expiresAt()` method's `$expiration` parameter is untyped +in the interface, but in the docblock is specified as `\DateTimeInterface`. The +intent is that either a `\DateTime` or `\DateTimeImmutable` object is allowed. +However, `\DateTimeInterface` and `\DateTimeImmutable` were added in PHP 5.5, and +the authors chose not to impose a hard syntactic requirement for PHP 5.5 on the +specification. + +Despite that, implementers MUST accept only `\DateTimeInterface` or compatible types +(such as `\DateTime` and `\DateTimeImmutable`) as if the method was explicitly typed. +(Note that the variance rules for a typed parameter may vary between language versions.) + +Simulating a failed type check unfortunately varies between PHP versions and thus is not +recommended. Instead, implementors SHOULD throw an instance of `\Psr\Cache\InvalidArgumentException`. +The following sample code is recommended in order to enforce the type check on the expiresAt() +method: + +```php + +class ExpiresAtInvalidParameterException implements Psr\Cache\InvalidArgumentException {} + +// ... + +if (! ( + null === $expiration + || $expiration instanceof \DateTime + || $expiration instanceof \DateTimeInterface +)) { + throw new ExpiresAtInvalidParameterException(sprintf( + 'Argument 1 passed to %s::expiresAt() must be an instance of DateTime or DateTimeImmutable; %s given', + get_class($this), + is_object($expiration) ? get_class($expiration) : gettype($expiration) + )); +} +``` diff --git a/_docs/psr/PSR-6-cache.md b/_docs/psr/PSR-6-cache.md index babf7ab..d245390 100644 --- a/_docs/psr/PSR-6-cache.md +++ b/_docs/psr/PSR-6-cache.md @@ -1,17 +1,4 @@ ---- -title: PRS-6 -category: PSRs -order: 5 ---- -| Informações Adicionais | -| ---------------------------------------------------| -| [Caching Interface][Caching Interface] | -| [Cache Meta Document][Cache Meta Document] | - -[Caching Interface]: #Caching Interface -[Cache Meta Document]: #Cache Meta Document - -

Caching Interface

+# Caching Interface Caching is a common way to improve the performance of any project, making caching libraries one of the most common features of many frameworks and @@ -451,340 +438,3 @@ interface InvalidArgumentException extends CacheException { } ~~~ - -

Cache Meta Document

- -## 1. Summary - -Caching is a common way to improve the performance of any project, making -caching libraries one of the most common features of many frameworks and -libraries. This has lead to a situation where many libraries roll their own -caching libraries, with various levels of functionality. These differences are -causing developers to have to learn multiple systems which may or may not -provide the functionality they need. In addition, the developers of caching -libraries themselves face a choice between only supporting a limited number -of frameworks or creating a large number of adapter classes. - -## 2. Why Bother? - -A common interface for caching systems will solve these problems. Library and -framework developers can count on the caching systems working the way they're -expecting, while the developers of caching systems will only have to implement -a single set of interfaces rather than a whole assortment of adapters. - -Moreover, the implementation presented here is designed for future extensibility. -It allows a variety of internally-different but API-compatible implementations -and offers a clear path for future extension by later PSRs or by specific -implementers. - -Pros: -* A standard interface for caching allows free-standing libraries to support -caching of intermediary data without effort; they may simply (optionally) depend -on this standard interface and leverage it without being concerned about -implementation details. -* Commonly developed caching libraries shared by multiple projects, even if -they extend this interface, are likely to be more robust than a dozen separately -developed implementations. - -Cons: -* Any interface standardization runs the risk of stifling future innovation as -being "not the Way It's Done(tm)". However, we believe caching is a sufficiently -commoditized problem space that the extension capability offered here mitigates -any potential risk of stagnation. - -## 3. Scope - -### 3.1 Goals - -* A common interface for basic and intermediate-level caching needs. -* A clear mechanism for extending the specification to support advanced features, -both by future PSRs or by individual implementations. This mechanism must allow -for multiple independent extensions without collision. - -### 3.2 Non-Goals - -* Architectural compatibility with all existing cache implementations. -* Advanced caching features such as namespacing or tagging that are used by a -minority of users. - -## 4. Approaches - -### 4.1 Chosen Approach - -This specification adopts a "repository model" or "data mapper" model for caching -rather than the more traditional "expire-able key-value" model. The primary -reason is flexibility. A simple key/value model is much more difficult to extend. - -The model here mandates the use of a CacheItem object, which represents a cache -entry, and a Pool object, which is a given store of cached data. Items are -retrieved from the pool, interacted with, and returned to it. While a bit more -verbose at times it offers a good, robust, flexible approach to caching, -especially in cases where caching is more involved than simply saving and -retrieving a string. - -Most method names were chosen based on common practice and method names in a -survey of member projects and other popular non-member systems. - -Pros: - -* Flexible and extensible -* Allows a great deal of variation in implementation without violating the interface -* Does not implicitly expose object constructors as a pseudo-interface. - -Cons: - -* A bit more verbose than the naive approach - -Examples: - -Some common usage patterns are shown below. These are non-normative but should -demonstrate the application of some design decisions. - -~~~php -/** - * Gets a list of available widgets. - * - * In this case, we assume the widget list changes so rarely that we want - * the list cached forever until an explicit clear. - */ -function get_widget_list() -{ - $pool = get_cache_pool('widgets'); - $item = $pool->getItem('widget_list'); - if (!$item->isHit()) { - $value = compute_expensive_widget_list(); - $item->set($value); - $pool->save($item); - } - return $item->get(); -} -~~~ - -~~~php -/** - * Caches a list of available widgets. - * - * In this case, we assume a list of widgets has been computed and we want - * to cache it, regardless of what may already be cached. - */ -function save_widget_list($list) -{ - $pool = get_cache_pool('widgets'); - $item = $pool->getItem('widget_list'); - $item->set($list); - $pool->save($item); -} -~~~ - -~~~php -/** - * Clears the list of available widgets. - * - * In this case, we simply want to remove the widget list from the cache. We - * don't care if it was set or not; the post condition is simply "no longer set". - */ -function clear_widget_list() -{ - $pool = get_cache_pool('widgets'); - $pool->deleteItems(['widget_list']); -} -~~~ - -~~~php -/** - * Clears all widget information. - * - * In this case, we want to empty the entire widget pool. There may be other - * pools in the application that will be unaffected. - */ -function clear_widget_cache() -{ - $pool = get_cache_pool('widgets'); - $pool->clear(); -} -~~~ - -~~~php -/** - * Load widgets. - * - * We want to get back a list of widgets, of which some are cached and some - * are not. This of course assumes that loading from the cache is faster than - * whatever the non-cached loading mechanism is. - * - * In this case, we assume widgets may change frequently so we only allow them - * to be cached for an hour (3600 seconds). We also cache newly-loaded objects - * back to the pool en masse. - * - * Note that a real implementation would probably also want a multi-load - * operation for widgets, but that's irrelevant for this demonstration. - */ -function load_widgets(array $ids) -{ - $pool = get_cache_pool('widgets'); - $keys = array_map(function($id) { return 'widget.' . $id; }, $ids); - $items = $pool->getItems($keys); - - $widgets = array(); - foreach ($items as $key => $item) { - if ($item->isHit()) { - $value = $item->get(); - } else { - $value = expensive_widget_load($id); - $item->set($value); - $item->expiresAfter(3600); - $pool->saveDeferred($item, true); - } - $widget[$value->id()] = $value; - } - $pool->commit(); // If no items were deferred this is a no-op. - - return $widgets; -} -~~~ - -~~~php -/** - * This examples reflects functionality that is NOT included in this - * specification, but is shown as an example of how such functionality MIGHT - * be added by extending implementations. - */ - -interface TaggablePoolInterface extends Psr\Cache\CachePoolInterface -{ - /** - * Clears only those items from the pool that have the specified tag. - */ - clearByTag($tag); -} - -interface TaggableItemInterface extends Psr\Cache\CacheItemInterface -{ - public function setTags(array $tags); -} - -/** - * Caches a widget with tags. - */ -function set_widget(TaggablePoolInterface $pool, Widget $widget) -{ - $key = 'widget.' . $widget->id(); - $item = $pool->getItem($key); - - $item->setTags($widget->tags()); - $item->set($widget); - $pool->save($item); -} -~~~ - -### 4.2 Alternative: "Weak item" approach - -A variety of earlier drafts took a simpler "key value with expiration" approach, -also known as a "weak item" approach. In this model, the "Cache Item" object -was really just a dumb array-with-methods object. Users would instantiate it -directly, then pass it to a cache pool. While more familiar, that approach -effectively prevented any meaningful extension of the Cache Item. It effectively -made the Cache Item's constructor part of the implicit interface, and thus -severely curtailed extensibility or the ability to have the cache item be where -the intelligence lives. - -In a poll conducted in June 2013, most participants showed a clear preference for -the more robust if less conventional "Strong item" / repository approach, which -was adopted as the way forward. - -Pros: -* More traditional approach. - -Cons: -* Less extensible or flexible. - -### 4.3 Alternative: "Naked value" approach - -Some of the earliest discussions of the Cache spec suggested skipping the Cache -Item concept all together and just reading/writing raw values to be cached. -While simpler, it was pointed out that made it impossible to tell the difference -between a cache miss and whatever raw value was selected to represent a cache -miss. That is, if a cache lookup returned NULL it's impossible to tell if there -was no cached value or if NULL was the value that had been cached. (NULL is a -legitimate value to cache in many cases.) - -Most more robust caching implementations we reviewed -- in particular the Stash -caching library and the home-grown cache system used by Drupal -- use some sort -of structured object on `get` at least to avoid confusion between a miss and a -sentinel value. Based on that prior experience FIG decided that a naked value -on `get` was impossible. - -### 4.4 Alternative: ArrayAccess Pool - -There was a suggestion to make a Pool implement ArrayAccess, which would allow -for cache get/set operations to use array syntax. That was rejected due to -limited interest, limited flexibility of that approach (trivial get and set with -default control information is all that's possible), and because it's trivial -for a particular implementation to include as an add-on should it desire to -do so. - -## 5. People - -### 5.1 Editor - -* Larry Garfield - -### 5.2 Sponsors - -* Paul Dragoonis, PPI Framework (Coordinator) -* Robert Hafner, Stash - -## 6. Votes - -[Acceptance vote on the mailing list](https://groups.google.com/forum/#!msg/php-fig/dSw5IhpKJ1g/O9wpqizWAwAJ) - -## 7. Relevant Links - -_**Note:** Order descending chronologically._ - -* [Survey of existing cache implementations][1], by @dragoonis -* [Strong vs. Weak informal poll][2], by @Crell -* [Implementation details informal poll][3], by @Crell - -[1]: https://docs.google.com/spreadsheet/ccc?key=0Ak2JdGialLildEM2UjlOdnA4ekg3R1Bfeng5eGlZc1E#gid=0 -[2]: https://docs.google.com/spreadsheet/ccc?key=0AsMrMKNHL1uGdDdVd2llN1kxczZQejZaa3JHcXA3b0E#gid=0 -[3]: https://docs.google.com/spreadsheet/ccc?key=0AsMrMKNHL1uGdEE3SU8zclNtdTNobWxpZnFyR0llSXc#gid=1 - -## 8. Errata - -### 8.1 Handling of incorrect DateTime values in expiresAt() - -The `CacheItemInterface::expiresAt()` method's `$expiration` parameter is untyped -in the interface, but in the docblock is specified as `\DateTimeInterface`. The -intent is that either a `\DateTime` or `\DateTimeImmutable` object is allowed. -However, `\DateTimeInterface` and `\DateTimeImmutable` were added in PHP 5.5, and -the authors chose not to impose a hard syntactic requirement for PHP 5.5 on the -specification. - -Despite that, implementers MUST accept only `\DateTimeInterface` or compatible types -(such as `\DateTime` and `\DateTimeImmutable`) as if the method was explicitly typed. -(Note that the variance rules for a typed parameter may vary between language versions.) - -Simulating a failed type check unfortunately varies between PHP versions and thus is not -recommended. Instead, implementors SHOULD throw an instance of `\Psr\Cache\InvalidArgumentException`. -The following sample code is recommended in order to enforce the type check on the expiresAt() -method: - -```php - -class ExpiresAtInvalidParameterException implements Psr\Cache\InvalidArgumentException {} - -// ... - -if (! ( - null === $expiration - || $expiration instanceof \DateTime - || $expiration instanceof \DateTimeInterface -)) { - throw new ExpiresAtInvalidParameterException(sprintf( - 'Argument 1 passed to %s::expiresAt() must be an instance of DateTime or DateTimeImmutable; %s given', - get_class($this), - is_object($expiration) ? get_class($expiration) : gettype($expiration) - )); -} -``` diff --git a/_docs/psr/PSR-7-http-message-meta.md b/_docs/psr/PSR-7-http-message-meta.md new file mode 100644 index 0000000..4b8a5bc --- /dev/null +++ b/_docs/psr/PSR-7-http-message-meta.md @@ -0,0 +1,649 @@ +# HTTP Message Meta Document + +## 1. Summary + +The purpose of this proposal is to provide a set of common interfaces for HTTP +messages as described in [RFC 7230](http://tools.ietf.org/html/rfc7230) and +[RFC 7231](http://tools.ietf.org/html/rfc7231), and URIs as described in +[RFC 3986](http://tools.ietf.org/html/rfc3986) (in the context of HTTP messages). + +- RFC 7230: http://www.ietf.org/rfc/rfc7230.txt +- RFC 7231: http://www.ietf.org/rfc/rfc7231.txt +- RFC 3986: http://www.ietf.org/rfc/rfc3986.txt + +All HTTP messages consist of the HTTP protocol version being used, headers, and +a message body. A _Request_ builds on the message to include the HTTP method +used to make the request, and the URI to which the request is made. A +_Response_ includes the HTTP status code and reason phrase. + +In PHP, HTTP messages are used in two contexts: + +- To send an HTTP request, via the `ext/curl` extension, PHP's native stream + layer, etc., and process the received HTTP response. In other words, HTTP + messages are used when using PHP as an _HTTP client_. +- To process an incoming HTTP request to the server, and return an HTTP response + to the client making the request. PHP can use HTTP messages when used as a + _server-side application_ to fulfill HTTP requests. + +This proposal presents an API for fully describing all parts of the various +HTTP messages within PHP. + +## 2. HTTP Messages in PHP + +PHP does not have built-in support for HTTP messages. + +### Client-side HTTP support + +PHP supports sending HTTP requests via several mechanisms: + +- [PHP streams](http://php.net/streams) +- The [cURL extension](http://php.net/curl) +- [ext/http](http://php.net/http) (v2 also attempts to address server-side support) + +PHP streams are the most convenient and ubiquitous way to send HTTP requests, +but pose a number of limitations with regards to properly configuring SSL +support, and provide a cumbersome interface around setting things such as +headers. cURL provides a complete and expanded feature-set, but, as it is not a +default extension, is often not present. The http extension suffers from the +same problem as cURL, as well as the fact that it has traditionally had far +fewer examples of usage. + +Most modern HTTP client libraries tend to abstract the implementation, to +ensure they can work on whatever environment they are executed on, and across +any of the above layers. + +### Server-side HTTP Support + +PHP uses Server APIs (SAPI) to interpret incoming HTTP requests, marshal input, +and pass off handling to scripts. The original SAPI design mirrored [Common +Gateway Interface](http://www.w3.org/CGI/), which would marshal request data +and push it into environment variables before passing delegation to a script; +the script would then pull from the environment variables in order to process +the request and return a response. + +PHP's SAPI design abstracts common input sources such as cookies, query string +arguments, and url-encoded POST content via superglobals (`$_COOKIE`, `$_GET`, +and `$_POST`, respectively), providing a layer of convenience for web developers. + +On the response side of the equation, PHP was originally developed as a +templating language, and allows intermixing HTML and PHP; any HTML portions of +a file are immediately flushed to the output buffer. Modern applications and +frameworks eschew this practice, as it can lead to issues with +regards to emitting a status line and/or response headers; they tend to +aggregate all headers and content, and emit them at once when all other +application processing is complete. Special care needs to be paid to ensure +that error reporting and other actions that send content to the output buffer +do not flush the output buffer. + +## 3. Why Bother? + +HTTP messages are used in a wide number of PHP projects -- both clients and +servers. In each case, we observe one or more of the following patterns or +situations: + +1. Projects use PHP's superglobals directly. +2. Projects will create implementations from scratch. +3. Projects may require a specific HTTP client/server library that provides + HTTP message implementations. +4. Projects may create adapters for common HTTP message implementations. + +As examples: + +1. Just about any application that began development before the rise of + frameworks, which includes a number of very popular CMS, forum, and shopping + cart systems, have historically used superglobals. +2. Frameworks such as Symfony and Zend Framework each define HTTP components + that form the basis of their MVC layers; even small, single-purpose + libraries such as oauth2-server-php provide and require their own HTTP + request/response implementations. Guzzle, Buzz, and other HTTP client + implementations each create their own HTTP message implementations as well. +3. Projects such as Silex, Stack, and Drupal 8 have hard dependencies on + Symfony's HTTP kernel. Any SDK built on Guzzle has a hard requirement on + Guzzle's HTTP message implementations. +4. Projects such as Geocoder create redundant [adapters for common + libraries](https://github.com/geocoder-php/Geocoder/tree/6a729c6869f55ad55ae641c74ac9ce7731635e6e/src/Geocoder/HttpAdapter). + +Direct usage of superglobals has a number of concerns. First, these are +mutable, which makes it possible for libraries and code to alter the values, +and thus alter state for the application. Additionally, superglobals make unit +and integration testing difficult and brittle, leading to code quality +degradation. + +In the current ecosystem of frameworks that implement HTTP message abstractions, +the net result is that projects are not capable of interoperability or +cross-pollination. In order to consume code targeting one framework from +another, the first order of business is building a bridge layer between the +HTTP message implementations. On the client-side, if a particular library does +not have an adapter you can utilize, you need to bridge the request/response +pairs if you wish to use an adapter from another library. + +Finally, when it comes to server-side responses, PHP gets in its own way: any +content emitted before a call to `header()` will result in that call becoming a +no-op; depending on error reporting settings, this can often mean headers +and/or response status are not correctly sent. One way to work around this is +to use PHP's output buffering features, but nesting of output buffers can +become problematic and difficult to debug. Frameworks and applications thus +tend to create response abstractions for aggregating headers and content that +can be emitted at once - and these abstractions are often incompatible. + +Thus, the goal of this proposal is to abstract both client- and server-side +request and response interfaces in order to promote interoperability between +projects. If projects implement these interfaces, a reasonable level of +compatibility may be assumed when adopting code from different libraries. + +It should be noted that the goal of this proposal is not to obsolete the +current interfaces utilized by existing PHP libraries. This proposal is aimed +at interoperability between PHP packages for the purpose of describing HTTP +messages. + +## 4. Scope + +### 4.1 Goals + +* Provide the interfaces needed for describing HTTP messages. +* Focus on practical applications and usability. +* Define the interfaces to model all elements of the HTTP message and URI + specifications. +* Ensure that the API does not impose arbitrary limits on HTTP messages. For + example, some HTTP message bodies can be too large to store in memory, so we + must account for this. +* Provide useful abstractions both for handling incoming requests for + server-side applications and for sending outgoing requests in HTTP clients. + +### 4.2 Non-Goals + +* This proposal does not expect all HTTP client libraries or server-side + frameworks to change their interfaces to conform. It is strictly meant for + interoperability. +* While everyone's perception of what is and is not an implementation detail + varies, this proposal should not impose implementation details. As + RFCs 7230, 7231, and 3986 do not force any particular implementation, + there will be a certain amount of invention needed to describe HTTP message + interfaces in PHP. + +## 5. Design Decisions + +### Message design + +The `MessageInterface` provides accessors for the elements common to all HTTP +messages, whether they are for requests or responses. These elements include: + +- HTTP protocol version (e.g., "1.0", "1.1") +- HTTP headers +- HTTP message body + +More specific interfaces are used to describe requests and responses, and more +specifically the context of each (client- vs. server-side). These divisions are +partly inspired by existing PHP usage, but also by other languages such as +Ruby's [Rack](https://rack.github.io), +Python's [WSGI](https://www.python.org/dev/peps/pep-0333/), +Go's [http package](http://golang.org/pkg/net/http/), +Node's [http module](http://nodejs.org/api/http.html), etc. + +### Why are there header methods on messages rather than in a header bag? + +The message itself is a container for the headers (as well as the other message +properties). How these are represented internally is an implementation detail, +but uniform access to headers is a responsibility of the message. + +### Why are URIs represented as objects? + +URIs are values, with identity defined by the value, and thus should be modeled +as value objects. + +Additionally, URIs contain a variety of segments which may be accessed many +times in a given request -- and which would require parsing the URI in order to +determine (e.g., via `parse_url()`). Modeling URIs as value objects allows +parsing once only, and simplifies access to individual segments. It also +provides convenience in client applications by allowing users to create new +instances of a base URI instance with only the segments that change (e.g., +updating the path only). + +### Why does the request interface have methods for dealing with the request-target AND compose a URI? + +RFC 7230 details the request line as containing a "request-target". Of the four +forms of request-target, only one is a URI compliant with RFC 3986; the most +common form used is origin-form, which represents the URI without the +scheme or authority information. Moreover, since all forms are valid for +purposes of requests, the proposal must accommodate each. + +`RequestInterface` thus has methods relating to the request-target. By default, +it will use the composed URI to present an origin-form request-target, and, in +the absence of a URI instance, return the string "/". Another method, +`withRequestTarget()`, allows specifying an instance with a specific +request-target, allowing users to create requests that use one of the other +valid request-target forms. + +The URI is kept as a discrete member of the request for a variety of reasons. +For both clients and servers, knowledge of the absolute URI is typically +required. In the case of clients, the URI, and specifically the scheme and +authority details, is needed in order to make the actual TCP connection. For +server-side applications, the full URI is often required in order to validate +the request or to route to an appropriate handler. + +### Why value objects? + +The proposal models messages and URIs as [value objects](http://en.wikipedia.org/wiki/Value_object). + +Messages are values where the identity is the aggregate of all parts of the +message; a change to any aspect of the message is essentially a new message. +This is the very definition of a value object. The practice by which changes +result in a new instance is termed [immutability](http://en.wikipedia.org/wiki/Immutable_object), +and is a feature designed to ensure the integrity of a given value. + +The proposal also recognizes that most clients and server-side +applications will need to be able to easily update message aspects, and, as +such, provides interface methods that will create new message instances with +the updates. These are generally prefixed with the verbiage `with` or +`without`. + +Value objects provides several benefits when modeling HTTP messages: + +- Changes in URI state cannot alter the request composing the URI instance. +- Changes in headers cannot alter the message composing them. + +In essence, modeling HTTP messages as value objects ensures the integrity of +the message state, and prevents the need for bi-directional dependencies, which +can often go out-of-sync or lead to debugging or performance issues. + +For HTTP clients, they allow consumers to build a base request with data such +as the base URI and required headers, without needing to build a brand new +request or reset request state for each message the client sends: + +~~~php +$uri = new Uri('http://api.example.com'); +$baseRequest = new Request($uri, null, [ + 'Authorization' => 'Bearer ' . $token, + 'Accept' => 'application/json', +]);; + +$request = $baseRequest->withUri($uri->withPath('/user'))->withMethod('GET'); +$response = $client->send($request); + +// get user id from $response + +$body = new StringStream(json_encode(['tasks' => [ + 'Code', + 'Coffee', +]]));; +$request = $baseRequest + ->withUri($uri->withPath('/tasks/user/' . $userId)) + ->withMethod('POST') + ->withHeader('Content-Type', 'application/json') + ->withBody($body); +$response = $client->send($request) + +// No need to overwrite headers or body! +$request = $baseRequest->withUri($uri->withPath('/tasks'))->withMethod('GET'); +$response = $client->send($request); +~~~ + +On the server-side, developers will need to: + +- Deserialize the request message body. +- Decrypt HTTP cookies. +- Write to the response. + +These operations can be accomplished with value objects as well, with a number +of benefits: + +- The original request state can be stored for retrieval by any consumer. +- A default response state can be created with default headers and/or message body. + +Most popular PHP frameworks have fully mutable HTTP messages today. The main +changes necessary in consuming true value objects are: + +- Instead of calling setter methods or setting public properties, mutator + methods will be called, and the result assigned. +- Developers must notify the application on a change in state. + +As an example, in Zend Framework 2, instead of the following: + +~~~php +function (MvcEvent $e) +{ + $response = $e->getResponse(); + $response->setHeaderLine('x-foo', 'bar'); +} +~~~ + +one would now write: + +~~~php +function (MvcEvent $e) +{ + $response = $e->getResponse(); + $e->setResponse( + $response->withHeader('x-foo', 'bar') + ); +} +~~~ + +The above combines assignment and notification in a single call. + +This practice has a side benefit of making explicit any changes to application +state being made. + +### New instances vs returning $this + +One observation made on the various `with*()` methods is that they can likely +safely `return $this;` if the argument presented will not result in a change in +the value. One rationale for doing so is performance (as this will not result in +a cloning operation). + +The various interfaces have been written with verbiage indicating that +immutability MUST be preserved, but only indicate that "an instance" must be +returned containing the new state. Since instances that represent the same value +are considered equal, returning `$this` is functionally equivalent, and thus +allowed. + +### Using streams instead of X + +`MessageInterface` uses a body value that must implement `StreamInterface`. This +design decision was made so that developers can send and receive (and/or receive +and send) HTTP messages that contain more data than can practically be stored in +memory while still allowing the convenience of interacting with message bodies +as a string. While PHP provides a stream abstraction by way of stream wrappers, +stream resources can be cumbersome to work with: stream resources can only be +cast to a string using `stream_get_contents()` or manually reading the remainder +of a string. Adding custom behavior to a stream as it is consumed or populated +requires registering a stream filter; however, stream filters can only be added +to a stream after the filter is registered with PHP (i.e., there is no stream +filter autoloading mechanism). + +The use of a well- defined stream interface allows for the potential of +flexible stream decorators that can be added to a request or response +pre-flight to enable things like encryption, compression, ensuring that the +number of bytes downloaded reflects the number of bytes reported in the +`Content-Length` of a response, etc. Decorating streams is a well-established +[pattern in the Java](http://docs.oracle.com/javase/7/docs/api/java/io/package-tree.html) +and [Node](http://nodejs.org/api/stream.html#stream_class_stream_transform_1) +communities that allows for very flexible streams. + +The majority of the `StreamInterface` API is based on +[Python's io module](http://docs.python.org/3.1/library/io.html), which provides +a practical and consumable API. Instead of implementing stream +capabilities using something like a `WritableStreamInterface` and +`ReadableStreamInterface`, the capabilities of a stream are provided by methods +like `isReadable()`, `isWritable()`, etc. This approach is used by Python, +[C#, C++](http://msdn.microsoft.com/en-us/library/system.io.stream.aspx), +[Ruby](http://www.ruby-doc.org/core-2.0.0/IO.html), +[Node](http://nodejs.org/api/stream.html), and likely others. + +#### What if I just want to return a file? + +In some cases, you may want to return a file from the filesystem. The typical +way to do this in PHP is one of the following: + +~~~php +readfile($filename); + +stream_copy_to_stream(fopen($filename, 'r'), fopen('php://output', 'w')); +~~~ + +Note that the above omits sending appropriate `Content-Type` and +`Content-Length` headers; the developer would need to emit these prior to +calling the above code. + +The equivalent using HTTP messages would be to use a `StreamInterface` +implementation that accepts a filename and/or stream resource, and to provide +this to the response instance. A complete example, including setting appropriate +headers: + +~~~php +// where Stream is a concrete StreamInterface: +$stream = new Stream($filename); +$finfo = new finfo(FILEINFO_MIME); +$response = $response + ->withHeader('Content-Type', $finfo->file($filename)) + ->withHeader('Content-Length', (string) filesize($filename)) + ->withBody($stream); +~~~ + +Emitting this response will send the file to the client. + +#### What if I want to directly emit output? + +Directly emitting output (e.g. via `echo`, `printf`, or writing to the +`php://output` stream) is generally only advisable as a performance optimization +or when emitting large data sets. If it needs to be done and you still wish +to work in an HTTP message paradigm, one approach would be to use a +callback-based `StreamInterface` implementation, per [this +example](https://github.com/phly/psr7examples#direct-output). Wrap any code +emitting output directly in a callback, pass that to an appropriate +`StreamInterface` implementation, and provide it to the message body: + +~~~php +$output = new CallbackStream(function () use ($request) { + printf("The requested URI was: %s
\n", $request->getUri()); + return ''; +}); +return (new Response()) + ->withHeader('Content-Type', 'text/html') + ->withBody($output); +~~~ + +#### What if I want to use an iterator for content? + +Ruby's Rack implementation uses an iterator-based approach for server-side +response message bodies. This can be emulated using an HTTP message paradigm via +an iterator-backed `StreamInterface` approach, as [detailed in the +psr7examples repository](https://github.com/phly/psr7examples#iterators-and-generators). + +### Why are streams mutable? + +The `StreamInterface` API includes methods such as `write()` which can +change the message content -- which directly contradicts having immutable +messages. + +The problem that arises is due to the fact that the interface is intended to +wrap a PHP stream or similar. A write operation therefore will proxy to writing +to the stream. Even if we made `StreamInterface` immutable, once the stream +has been updated, any instance that wraps that stream will also be updated -- +making immutability impossible to enforce. + +Our recommendation is that implementations use read-only streams for +server-side requests and client-side responses. + +### Rationale for ServerRequestInterface + +The `RequestInterface` and `ResponseInterface` have essentially 1:1 +correlations with the request and response messages described in +[RFC 7230](http://www.ietf.org/rfc/rfc7230.txt). They provide interfaces for +implementing value objects that correspond to the specific HTTP message types +they model. + +For server-side applications there are other considerations for +incoming requests: + +- Access to server parameters (potentially derived from the request, but also + potentially the result of server configuration, and generally represented + via the `$_SERVER` superglobal; these are part of the PHP Server API (SAPI)). +- Access to the query string arguments (usually encapsulated in PHP via the + `$_GET` superglobal). +- Access to the parsed body (i.e., data deserialized from the incoming request + body; in PHP, this is typically the result of POST requests using + `application/x-www-form-urlencoded` content types, and encapsulated in the + `$_POST` superglobal, but for non-POST, non-form-encoded data, could be + an array or an object). +- Access to uploaded files (encapsulated in PHP via the `$_FILES` superglobal). +- Access to cookie values (encapsulated in PHP via the `$_COOKIE` superglobal). +- Access to attributes derived from the request (usually, but not limited to, + those matched against the URL path). + +Uniform access to these parameters increases the viability of interoperability +between frameworks and libraries, as they can now assume that if a request +implements `ServerRequestInterface`, they can get at these values. It also +solves problems within the PHP language itself: + +- Until 5.6.0, `php://input` was read-once; as such, instantiating multiple + request instances from multiple frameworks/libraries could lead to + inconsistent state, as the first to access `php://input` would be the only + one to receive the data. +- Unit testing against superglobals (e.g., `$_GET`, `$_FILES`, etc.) is + difficult and typically brittle. Encapsulating them inside the + `ServerRequestInterface` implementation eases testing considerations. + +### Why "parsed body" in the ServerRequestInterface? + +Arguments were made to use the terminology "BodyParams", and require the value +to be an array, with the following rationale: + +- Consistency with other server-side parameter access. +- `$_POST` is an array, and the 80% use case would target that superglobal. +- A single type makes for a strong contract, simplifying usage. + +The main argument is that if the body parameters are an array, developers have +predictable access to values: + +~~~php +$foo = isset($request->getBodyParams()['foo']) + ? $request->getBodyParams()['foo'] + : null; +~~~ + +The argument for using "parsed body" was made by examining the domain. A message +body can contain literally anything. While traditional web applications use +forms and submit data using POST, this is a use case that is quickly being +challenged in current web development trends, which are often API-centric, and +thus use alternate request methods (notably PUT and PATCH), as well as +non-form-encoded content (generally JSON or XML) that _can_ be coerced to arrays +in many cases, but in many cases also _cannot_ or _should not_. + +If forcing the property representing the parsed body to be only an array, +developers then need a shared convention about where to put the results of +parsing the body. These might include: + +- A special key under the body parameters, such as `__parsed__`. +- A specially named attribute, such as `__body__`. + +The end result is that a developer now has to look in multiple locations: + +~~~php +$data = $request->getBodyParams(); +if (isset($data['__parsed__']) && is_object($data['__parsed__'])) { + $data = $data['__parsed__']; +} + +// or: +$data = $request->getBodyParams(); +if ($request->hasAttribute('__body__')) { + $data = $request->getAttribute('__body__'); +} +~~~ + +The solution presented is to use the terminology "ParsedBody", which implies +that the values are the results of parsing the message body. This also means +that the return value _will_ be ambiguous; however, because this is an attribute +of the domain, this is also expected. As such, usage will become: + +~~~php +$data = $request->getParsedBody(); +if (! $data instanceof \stdClass) { + // raise an exception! +} +// otherwise, we have what we expected +~~~ + +This approach removes the limitations of forcing an array, at the expense of +ambiguity of return value. Considering that the other suggested solutions — +pushing the parsed data into a special body parameter key or into an attribute — +also suffer from ambiguity, the proposed solution is simpler as it does not +require additions to the interface specification. Ultimately, the ambiguity +enables the flexibility required when representing the results of parsing the +body. + +### Why is no functionality included for retrieving the "base path"? + +Many frameworks provide the ability to get the "base path," usually considered +the path up to and including the front controller. As an example, if the +application is served at `http://example.com/b2b/index.php`, and the current URI +used to request it is `http://example.com/b2b/index.php/customer/register`, the +functionality to retrieve the base path would return `/b2b/index.php`. This value +can then be used by routers to strip that path segment prior to attempting a +match. + +This value is often also then used for URI generation within applications; +parameters will be passed to the router, which will generate the path, and +prefix it with the base path in order to return a fully-qualified URI. Other +tools — typically view helpers, template filters, or template functions — are +used to resolve a path relative to the base path in order to generate a URI for +linking to resources such as static assets. + +On examination of several different implementations, we noticed the following: + +- The logic for determining the base path varies widely between implementations. + As an example, compare the [logic in ZF2](https://github.com/zendframework/zf2/blob/release-2.3.7/library/Zend/Http/PhpEnvironment/Request.php#L477-L575) + to the [logic in Symfony 2](https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/HttpFoundation/Request.php#L1858-L1877). +- Most implementations appear to allow manual injection of a base path to the + router and/or any facilities used for URI generation. +- The primary use cases — routing and URI generation — typically are the only + consumers of the functionality; developers usually do not need to be aware + of the base path concept as other objects take care of that detail for them. + As examples: + - A router will strip off the base path for you during routing; you do not + need to pass the modified path to the router. + - View helpers, template filters, etc. typically are injected with a base path + prior to invocation. Sometimes this is manually done, though more often it + is the result of framework wiring. +- All sources necessary for calculating the base path *are already in the + `RequestInterface` instance*, via server parameters and the URI instance. + +Our stance is that base path detection is framework and/or application +specific, and the results of detection can be easily injected into objects that +need it, and/or calculated as needed using utility functions and/or classes from +the `RequestInterface` instance itself. + +### Why does getUploadedFiles() return objects instead of arrays? + +`getUploadedFiles()` returns a tree of `Psr\Http\Message\UploadedFileInterface` +instances. This is done primarily to simplify specification: instead of +requiring paragraphs of implementation specification for an array, we specify an +interface. + +Additionally, the data in an `UploadedFileInterface` is normalized to work in +both SAPI and non-SAPI environments. This allows the creation of processes to parse +the message body manually and assign contents to streams without first writing +to the filesystem, while still allowing proper handling of file uploads in SAPI +environments. + +### What about "special" header values? + +A number of header values contain unique representation requirements which can +pose problems both for consumption as well as generation; in particular, cookies +and the `Accept` header. + +This proposal does not provide any special treatment of any header types. The +base `MessageInterface` provides methods for header retrieval and setting, and +all header values are, in the end, string values. + +Developers are encouraged to write commodity libraries for interacting with +these header values, either for the purposes of parsing or generation. Users may +then consume these libraries when needing to interact with those values. +Examples of this practice already exist in libraries such as +[willdurand/Negotiation](https://github.com/willdurand/Negotiation) and +[Aura.Accept](https://github.com/auraphp/Aura.Accept). So long as the object +has functionality for casting the value to a string, these objects can be +used to populate the headers of an HTTP message. + +## 6. People + +### 6.1 Editor(s) + +* Matthew Weier O'Phinney + +### 6.2 Sponsors + +* Paul M. Jones +* Beau Simensen (coordinator) + +### 6.3 Contributors + +* Michael Dowling +* Larry Garfield +* Evert Pot +* Tobias Schultze +* Bernhard Schussek +* Anton Serdyuk +* Phil Sturgeon +* Chris Wilkinson diff --git a/_docs/psr/PSR-7-http-message.md b/_docs/psr/PSR-7-http-message.md index a26f95a..419f7de 100644 --- a/_docs/psr/PSR-7-http-message.md +++ b/_docs/psr/PSR-7-http-message.md @@ -1,18 +1,4 @@ ---- -title: PRS-7 -category: PSRs -order: 6 ---- - -| Informações Adicionais | -| -----------------------------------------------------------------| -| [HTTP message interfaces][HTTP message interfaces] | -| [HTTP Message Meta Document][HTTP Message Meta Document] | - -[HTTP message interfaces]: #HTTP message interfaces -[HTTP Message Meta Document]: #HTTP Message Meta Document - -

HTTP message interfaces

+# HTTP message interfaces This document describes common interfaces for representing HTTP messages as described in [RFC 7230](http://tools.ietf.org/html/rfc7230) and @@ -446,15 +432,31 @@ In the case of an input using array notation for the name: `$_FILES` ends up looking like this: ~~~php -array( - 'my-form' => array( - 'details' => array( - 'avatar' => array( - 'tmp_name' => 'phpUxcOty', - 'name' => 'my-avatar.png', - 'size' => 90996, - 'type' => 'image/png', - 'error' => 0, +array ( + 'my-form' => array ( + 'name' => array ( + 'details' => array ( + 'avatar' => 'my-avatar.png', + ), + ), + 'type' => array ( + 'details' => array ( + 'avatar' => 'image/png', + ), + ), + 'tmp_name' => array ( + 'details' => array ( + 'avatar' => 'phpmFLrzD', + ), + ), + 'error' => array ( + 'details' => array ( + 'avatar' => 0, + ), + ), + 'size' => array ( + 'details' => array ( + 'avatar' => 90996, ), ), ), @@ -488,34 +490,50 @@ related to the file at the given index. The reason is because `$_FILES` deviates from its normal structure in such cases: ~~~php -array( - 'my-form' => array( - 'details' => array( - 'avatars' => array( - 'tmp_name' => array( - 0 => '...', - 1 => '...', - 2 => '...', +array ( + 'my-form' => array ( + 'name' => array ( + 'details' => array ( + 'avatar' => array ( + 0 => 'my-avatar.png', + 1 => 'my-avatar2.png', + 2 => 'my-avatar3.png', ), - 'name' => array( - 0 => '...', - 1 => '...', - 2 => '...', + ), + ), + 'type' => array ( + 'details' => array ( + 'avatar' => array ( + 0 => 'image/png', + 1 => 'image/png', + 2 => 'image/png', ), - 'size' => array( - 0 => '...', - 1 => '...', - 2 => '...', + ), + ), + 'tmp_name' => array ( + 'details' => array ( + 'avatar' => array ( + 0 => 'phpmFLrzD', + 1 => 'phpV2pBil', + 2 => 'php8RUG8v', ), - 'type' => array( - 0 => '...', - 1 => '...', - 2 => '...', + ), + ), + 'error' => array ( + 'details' => array ( + 'avatar' => array ( + 0 => 0, + 1 => 0, + 2 => 0, ), - 'error' => array( - 0 => '...', - 1 => '...', - 2 => '...', + ), + ), + 'size' => array ( + 'details' => array ( + 'avatar' => array ( + 0 => 90996, + 1 => 90996, + 3 => 90996, ), ), ), @@ -1883,654 +1901,3 @@ interface UploadedFileInterface public function getClientMediaType(); } ~~~ - - -

HTTP Message Meta Document

- -## 1. Summary - -The purpose of this proposal is to provide a set of common interfaces for HTTP -messages as described in [RFC 7230](http://tools.ietf.org/html/rfc7230) and -[RFC 7231](http://tools.ietf.org/html/rfc7231), and URIs as described in -[RFC 3986](http://tools.ietf.org/html/rfc3986) (in the context of HTTP messages). - -- RFC 7230: http://www.ietf.org/rfc/rfc7230.txt -- RFC 7231: http://www.ietf.org/rfc/rfc7231.txt -- RFC 3986: http://www.ietf.org/rfc/rfc3986.txt - -All HTTP messages consist of the HTTP protocol version being used, headers, and -a message body. A _Request_ builds on the message to include the HTTP method -used to make the request, and the URI to which the request is made. A -_Response_ includes the HTTP status code and reason phrase. - -In PHP, HTTP messages are used in two contexts: - -- To send an HTTP request, via the `ext/curl` extension, PHP's native stream - layer, etc., and process the received HTTP response. In other words, HTTP - messages are used when using PHP as an _HTTP client_. -- To process an incoming HTTP request to the server, and return an HTTP response - to the client making the request. PHP can use HTTP messages when used as a - _server-side application_ to fulfill HTTP requests. - -This proposal presents an API for fully describing all parts of the various -HTTP messages within PHP. - -## 2. HTTP Messages in PHP - -PHP does not have built-in support for HTTP messages. - -### Client-side HTTP support - -PHP supports sending HTTP requests via several mechanisms: - -- [PHP streams](http://php.net/streams) -- The [cURL extension](http://php.net/curl) -- [ext/http](http://php.net/http) (v2 also attempts to address server-side support) - -PHP streams are the most convenient and ubiquitous way to send HTTP requests, -but pose a number of limitations with regards to properly configuring SSL -support, and provide a cumbersome interface around setting things such as -headers. cURL provides a complete and expanded feature-set, but, as it is not a -default extension, is often not present. The http extension suffers from the -same problem as cURL, as well as the fact that it has traditionally had far -fewer examples of usage. - -Most modern HTTP client libraries tend to abstract the implementation, to -ensure they can work on whatever environment they are executed on, and across -any of the above layers. - -### Server-side HTTP Support - -PHP uses Server APIs (SAPI) to interpret incoming HTTP requests, marshal input, -and pass off handling to scripts. The original SAPI design mirrored [Common -Gateway Interface](http://www.w3.org/CGI/), which would marshal request data -and push it into environment variables before passing delegation to a script; -the script would then pull from the environment variables in order to process -the request and return a response. - -PHP's SAPI design abstracts common input sources such as cookies, query string -arguments, and url-encoded POST content via superglobals (`$_COOKIE`, `$_GET`, -and `$_POST`, respectively), providing a layer of convenience for web developers. - -On the response side of the equation, PHP was originally developed as a -templating language, and allows intermixing HTML and PHP; any HTML portions of -a file are immediately flushed to the output buffer. Modern applications and -frameworks eschew this practice, as it can lead to issues with -regards to emitting a status line and/or response headers; they tend to -aggregate all headers and content, and emit them at once when all other -application processing is complete. Special care needs to be paid to ensure -that error reporting and other actions that send content to the output buffer -do not flush the output buffer. - -## 3. Why Bother? - -HTTP messages are used in a wide number of PHP projects -- both clients and -servers. In each case, we observe one or more of the following patterns or -situations: - -1. Projects use PHP's superglobals directly. -2. Projects will create implementations from scratch. -3. Projects may require a specific HTTP client/server library that provides - HTTP message implementations. -4. Projects may create adapters for common HTTP message implementations. - -As examples: - -1. Just about any application that began development before the rise of - frameworks, which includes a number of very popular CMS, forum, and shopping - cart systems, have historically used superglobals. -2. Frameworks such as Symfony and Zend Framework each define HTTP components - that form the basis of their MVC layers; even small, single-purpose - libraries such as oauth2-server-php provide and require their own HTTP - request/response implementations. Guzzle, Buzz, and other HTTP client - implementations each create their own HTTP message implementations as well. -3. Projects such as Silex, Stack, and Drupal 8 have hard dependencies on - Symfony's HTTP kernel. Any SDK built on Guzzle has a hard requirement on - Guzzle's HTTP message implementations. -4. Projects such as Geocoder create redundant [adapters for common - libraries](https://github.com/geocoder-php/Geocoder/tree/6a729c6869f55ad55ae641c74ac9ce7731635e6e/src/Geocoder/HttpAdapter). - -Direct usage of superglobals has a number of concerns. First, these are -mutable, which makes it possible for libraries and code to alter the values, -and thus alter state for the application. Additionally, superglobals make unit -and integration testing difficult and brittle, leading to code quality -degradation. - -In the current ecosystem of frameworks that implement HTTP message abstractions, -the net result is that projects are not capable of interoperability or -cross-pollination. In order to consume code targeting one framework from -another, the first order of business is building a bridge layer between the -HTTP message implementations. On the client-side, if a particular library does -not have an adapter you can utilize, you need to bridge the request/response -pairs if you wish to use an adapter from another library. - -Finally, when it comes to server-side responses, PHP gets in its own way: any -content emitted before a call to `header()` will result in that call becoming a -no-op; depending on error reporting settings, this can often mean headers -and/or response status are not correctly sent. One way to work around this is -to use PHP's output buffering features, but nesting of output buffers can -become problematic and difficult to debug. Frameworks and applications thus -tend to create response abstractions for aggregating headers and content that -can be emitted at once - and these abstractions are often incompatible. - -Thus, the goal of this proposal is to abstract both client- and server-side -request and response interfaces in order to promote interoperability between -projects. If projects implement these interfaces, a reasonable level of -compatibility may be assumed when adopting code from different libraries. - -It should be noted that the goal of this proposal is not to obsolete the -current interfaces utilized by existing PHP libraries. This proposal is aimed -at interoperability between PHP packages for the purpose of describing HTTP -messages. - -## 4. Scope - -### 4.1 Goals - -* Provide the interfaces needed for describing HTTP messages. -* Focus on practical applications and usability. -* Define the interfaces to model all elements of the HTTP message and URI - specifications. -* Ensure that the API does not impose arbitrary limits on HTTP messages. For - example, some HTTP message bodies can be too large to store in memory, so we - must account for this. -* Provide useful abstractions both for handling incoming requests for - server-side applications and for sending outgoing requests in HTTP clients. - -### 4.2 Non-Goals - -* This proposal does not expect all HTTP client libraries or server-side - frameworks to change their interfaces to conform. It is strictly meant for - interoperability. -* While everyone's perception of what is and is not an implementation detail - varies, this proposal should not impose implementation details. As - RFCs 7230, 7231, and 3986 do not force any particular implementation, - there will be a certain amount of invention needed to describe HTTP message - interfaces in PHP. - -## 5. Design Decisions - -### Message design - -The `MessageInterface` provides accessors for the elements common to all HTTP -messages, whether they are for requests or responses. These elements include: - -- HTTP protocol version (e.g., "1.0", "1.1") -- HTTP headers -- HTTP message body - -More specific interfaces are used to describe requests and responses, and more -specifically the context of each (client- vs. server-side). These divisions are -partly inspired by existing PHP usage, but also by other languages such as -Ruby's [Rack](https://rack.github.io), -Python's [WSGI](https://www.python.org/dev/peps/pep-0333/), -Go's [http package](http://golang.org/pkg/net/http/), -Node's [http module](http://nodejs.org/api/http.html), etc. - -### Why are there header methods on messages rather than in a header bag? - -The message itself is a container for the headers (as well as the other message -properties). How these are represented internally is an implementation detail, -but uniform access to headers is a responsibility of the message. - -### Why are URIs represented as objects? - -URIs are values, with identity defined by the value, and thus should be modeled -as value objects. - -Additionally, URIs contain a variety of segments which may be accessed many -times in a given request -- and which would require parsing the URI in order to -determine (e.g., via `parse_url()`). Modeling URIs as value objects allows -parsing once only, and simplifies access to individual segments. It also -provides convenience in client applications by allowing users to create new -instances of a base URI instance with only the segments that change (e.g., -updating the path only). - -### Why does the request interface have methods for dealing with the request-target AND compose a URI? - -RFC 7230 details the request line as containing a "request-target". Of the four -forms of request-target, only one is a URI compliant with RFC 3986; the most -common form used is origin-form, which represents the URI without the -scheme or authority information. Moreover, since all forms are valid for -purposes of requests, the proposal must accommodate each. - -`RequestInterface` thus has methods relating to the request-target. By default, -it will use the composed URI to present an origin-form request-target, and, in -the absence of a URI instance, return the string "/". Another method, -`withRequestTarget()`, allows specifying an instance with a specific -request-target, allowing users to create requests that use one of the other -valid request-target forms. - -The URI is kept as a discrete member of the request for a variety of reasons. -For both clients and servers, knowledge of the absolute URI is typically -required. In the case of clients, the URI, and specifically the scheme and -authority details, is needed in order to make the actual TCP connection. For -server-side applications, the full URI is often required in order to validate -the request or to route to an appropriate handler. - -### Why value objects? - -The proposal models messages and URIs as [value objects](http://en.wikipedia.org/wiki/Value_object). - -Messages are values where the identity is the aggregate of all parts of the -message; a change to any aspect of the message is essentially a new message. -This is the very definition of a value object. The practice by which changes -result in a new instance is termed [immutability](http://en.wikipedia.org/wiki/Immutable_object), -and is a feature designed to ensure the integrity of a given value. - -The proposal also recognizes that most clients and server-side -applications will need to be able to easily update message aspects, and, as -such, provides interface methods that will create new message instances with -the updates. These are generally prefixed with the verbiage `with` or -`without`. - -Value objects provides several benefits when modeling HTTP messages: - -- Changes in URI state cannot alter the request composing the URI instance. -- Changes in headers cannot alter the message composing them. - -In essence, modeling HTTP messages as value objects ensures the integrity of -the message state, and prevents the need for bi-directional dependencies, which -can often go out-of-sync or lead to debugging or performance issues. - -For HTTP clients, they allow consumers to build a base request with data such -as the base URI and required headers, without needing to build a brand new -request or reset request state for each message the client sends: - -~~~php -$uri = new Uri('http://api.example.com'); -$baseRequest = new Request($uri, null, [ - 'Authorization' => 'Bearer ' . $token, - 'Accept' => 'application/json', -]);; - -$request = $baseRequest->withUri($uri->withPath('/user'))->withMethod('GET'); -$response = $client->send($request); - -// get user id from $response - -$body = new StringStream(json_encode(['tasks' => [ - 'Code', - 'Coffee', -]]));; -$request = $baseRequest - ->withUri($uri->withPath('/tasks/user/' . $userId)) - ->withMethod('POST') - ->withHeader('Content-Type', 'application/json') - ->withBody($body); -$response = $client->send($request) - -// No need to overwrite headers or body! -$request = $baseRequest->withUri($uri->withPath('/tasks'))->withMethod('GET'); -$response = $client->send($request); -~~~ - -On the server-side, developers will need to: - -- Deserialize the request message body. -- Decrypt HTTP cookies. -- Write to the response. - -These operations can be accomplished with value objects as well, with a number -of benefits: - -- The original request state can be stored for retrieval by any consumer. -- A default response state can be created with default headers and/or message body. - -Most popular PHP frameworks have fully mutable HTTP messages today. The main -changes necessary in consuming true value objects are: - -- Instead of calling setter methods or setting public properties, mutator - methods will be called, and the result assigned. -- Developers must notify the application on a change in state. - -As an example, in Zend Framework 2, instead of the following: - -~~~php -function (MvcEvent $e) -{ - $response = $e->getResponse(); - $response->setHeaderLine('x-foo', 'bar'); -} -~~~ - -one would now write: - -~~~php -function (MvcEvent $e) -{ - $response = $e->getResponse(); - $e->setResponse( - $response->withHeader('x-foo', 'bar') - ); -} -~~~ - -The above combines assignment and notification in a single call. - -This practice has a side benefit of making explicit any changes to application -state being made. - -### New instances vs returning $this - -One observation made on the various `with*()` methods is that they can likely -safely `return $this;` if the argument presented will not result in a change in -the value. One rationale for doing so is performance (as this will not result in -a cloning operation). - -The various interfaces have been written with verbiage indicating that -immutability MUST be preserved, but only indicate that "an instance" must be -returned containing the new state. Since instances that represent the same value -are considered equal, returning `$this` is functionally equivalent, and thus -allowed. - -### Using streams instead of X - -`MessageInterface` uses a body value that must implement `StreamInterface`. This -design decision was made so that developers can send and receive (and/or receive -and send) HTTP messages that contain more data than can practically be stored in -memory while still allowing the convenience of interacting with message bodies -as a string. While PHP provides a stream abstraction by way of stream wrappers, -stream resources can be cumbersome to work with: stream resources can only be -cast to a string using `stream_get_contents()` or manually reading the remainder -of a string. Adding custom behavior to a stream as it is consumed or populated -requires registering a stream filter; however, stream filters can only be added -to a stream after the filter is registered with PHP (i.e., there is no stream -filter autoloading mechanism). - -The use of a well- defined stream interface allows for the potential of -flexible stream decorators that can be added to a request or response -pre-flight to enable things like encryption, compression, ensuring that the -number of bytes downloaded reflects the number of bytes reported in the -`Content-Length` of a response, etc. Decorating streams is a well-established -[pattern in the Java](http://docs.oracle.com/javase/7/docs/api/java/io/package-tree.html) -and [Node](http://nodejs.org/api/stream.html#stream_class_stream_transform_1) -communities that allows for very flexible streams. - -The majority of the `StreamInterface` API is based on -[Python's io module](http://docs.python.org/3.1/library/io.html), which provides -a practical and consumable API. Instead of implementing stream -capabilities using something like a `WritableStreamInterface` and -`ReadableStreamInterface`, the capabilities of a stream are provided by methods -like `isReadable()`, `isWritable()`, etc. This approach is used by Python, -[C#, C++](http://msdn.microsoft.com/en-us/library/system.io.stream.aspx), -[Ruby](http://www.ruby-doc.org/core-2.0.0/IO.html), -[Node](http://nodejs.org/api/stream.html), and likely others. - -#### What if I just want to return a file? - -In some cases, you may want to return a file from the filesystem. The typical -way to do this in PHP is one of the following: - -~~~php -readfile($filename); - -stream_copy_to_stream(fopen($filename, 'r'), fopen('php://output', 'w')); -~~~ - -Note that the above omits sending appropriate `Content-Type` and -`Content-Length` headers; the developer would need to emit these prior to -calling the above code. - -The equivalent using HTTP messages would be to use a `StreamInterface` -implementation that accepts a filename and/or stream resource, and to provide -this to the response instance. A complete example, including setting appropriate -headers: - -~~~php -// where Stream is a concrete StreamInterface: -$stream = new Stream($filename); -$finfo = new finfo(FILEINFO_MIME); -$response = $response - ->withHeader('Content-Type', $finfo->file($filename)) - ->withHeader('Content-Length', (string) filesize($filename)) - ->withBody($stream); -~~~ - -Emitting this response will send the file to the client. - -#### What if I want to directly emit output? - -Directly emitting output (e.g. via `echo`, `printf`, or writing to the -`php://output` stream) is generally only advisable as a performance optimization -or when emitting large data sets. If it needs to be done and you still wish -to work in an HTTP message paradigm, one approach would be to use a -callback-based `StreamInterface` implementation, per [this -example](https://github.com/phly/psr7examples#direct-output). Wrap any code -emitting output directly in a callback, pass that to an appropriate -`StreamInterface` implementation, and provide it to the message body: - -~~~php -$output = new CallbackStream(function () use ($request) { - printf("The requested URI was: %s
\n", $request->getUri()); - return ''; -}); -return (new Response()) - ->withHeader('Content-Type', 'text/html') - ->withBody($output); -~~~ - -#### What if I want to use an iterator for content? - -Ruby's Rack implementation uses an iterator-based approach for server-side -response message bodies. This can be emulated using an HTTP message paradigm via -an iterator-backed `StreamInterface` approach, as [detailed in the -psr7examples repository](https://github.com/phly/psr7examples#iterators-and-generators). - -### Why are streams mutable? - -The `StreamInterface` API includes methods such as `write()` which can -change the message content -- which directly contradicts having immutable -messages. - -The problem that arises is due to the fact that the interface is intended to -wrap a PHP stream or similar. A write operation therefore will proxy to writing -to the stream. Even if we made `StreamInterface` immutable, once the stream -has been updated, any instance that wraps that stream will also be updated -- -making immutability impossible to enforce. - -Our recommendation is that implementations use read-only streams for -server-side requests and client-side responses. - -### Rationale for ServerRequestInterface - -The `RequestInterface` and `ResponseInterface` have essentially 1:1 -correlations with the request and response messages described in -[RFC 7230](http://www.ietf.org/rfc/rfc7230.txt). They provide interfaces for -implementing value objects that correspond to the specific HTTP message types -they model. - -For server-side applications there are other considerations for -incoming requests: - -- Access to server parameters (potentially derived from the request, but also - potentially the result of server configuration, and generally represented - via the `$_SERVER` superglobal; these are part of the PHP Server API (SAPI)). -- Access to the query string arguments (usually encapsulated in PHP via the - `$_GET` superglobal). -- Access to the parsed body (i.e., data deserialized from the incoming request - body; in PHP, this is typically the result of POST requests using - `application/x-www-form-urlencoded` content types, and encapsulated in the - `$_POST` superglobal, but for non-POST, non-form-encoded data, could be - an array or an object). -- Access to uploaded files (encapsulated in PHP via the `$_FILES` superglobal). -- Access to cookie values (encapsulated in PHP via the `$_COOKIE` superglobal). -- Access to attributes derived from the request (usually, but not limited to, - those matched against the URL path). - -Uniform access to these parameters increases the viability of interoperability -between frameworks and libraries, as they can now assume that if a request -implements `ServerRequestInterface`, they can get at these values. It also -solves problems within the PHP language itself: - -- Until 5.6.0, `php://input` was read-once; as such, instantiating multiple - request instances from multiple frameworks/libraries could lead to - inconsistent state, as the first to access `php://input` would be the only - one to receive the data. -- Unit testing against superglobals (e.g., `$_GET`, `$_FILES`, etc.) is - difficult and typically brittle. Encapsulating them inside the - `ServerRequestInterface` implementation eases testing considerations. - -### Why "parsed body" in the ServerRequestInterface? - -Arguments were made to use the terminology "BodyParams", and require the value -to be an array, with the following rationale: - -- Consistency with other server-side parameter access. -- `$_POST` is an array, and the 80% use case would target that superglobal. -- A single type makes for a strong contract, simplifying usage. - -The main argument is that if the body parameters are an array, developers have -predictable access to values: - -~~~php -$foo = isset($request->getBodyParams()['foo']) - ? $request->getBodyParams()['foo'] - : null; -~~~ - -The argument for using "parsed body" was made by examining the domain. A message -body can contain literally anything. While traditional web applications use -forms and submit data using POST, this is a use case that is quickly being -challenged in current web development trends, which are often API-centric, and -thus use alternate request methods (notably PUT and PATCH), as well as -non-form-encoded content (generally JSON or XML) that _can_ be coerced to arrays -in many cases, but in many cases also _cannot_ or _should not_. - -If forcing the property representing the parsed body to be only an array, -developers then need a shared convention about where to put the results of -parsing the body. These might include: - -- A special key under the body parameters, such as `__parsed__`. -- A specially named attribute, such as `__body__`. - -The end result is that a developer now has to look in multiple locations: - -~~~php -$data = $request->getBodyParams(); -if (isset($data['__parsed__']) && is_object($data['__parsed__'])) { - $data = $data['__parsed__']; -} - -// or: -$data = $request->getBodyParams(); -if ($request->hasAttribute('__body__')) { - $data = $request->getAttribute('__body__'); -} -~~~ - -The solution presented is to use the terminology "ParsedBody", which implies -that the values are the results of parsing the message body. This also means -that the return value _will_ be ambiguous; however, because this is an attribute -of the domain, this is also expected. As such, usage will become: - -~~~php -$data = $request->getParsedBody(); -if (! $data instanceof \stdClass) { - // raise an exception! -} -// otherwise, we have what we expected -~~~ - -This approach removes the limitations of forcing an array, at the expense of -ambiguity of return value. Considering that the other suggested solutions — -pushing the parsed data into a special body parameter key or into an attribute — -also suffer from ambiguity, the proposed solution is simpler as it does not -require additions to the interface specification. Ultimately, the ambiguity -enables the flexibility required when representing the results of parsing the -body. - -### Why is no functionality included for retrieving the "base path"? - -Many frameworks provide the ability to get the "base path," usually considered -the path up to and including the front controller. As an example, if the -application is served at `http://example.com/b2b/index.php`, and the current URI -used to request it is `http://example.com/b2b/index.php/customer/register`, the -functionality to retrieve the base path would return `/b2b/index.php`. This value -can then be used by routers to strip that path segment prior to attempting a -match. - -This value is often also then used for URI generation within applications; -parameters will be passed to the router, which will generate the path, and -prefix it with the base path in order to return a fully-qualified URI. Other -tools — typically view helpers, template filters, or template functions — are -used to resolve a path relative to the base path in order to generate a URI for -linking to resources such as static assets. - -On examination of several different implementations, we noticed the following: - -- The logic for determining the base path varies widely between implementations. - As an example, compare the [logic in ZF2](https://github.com/zendframework/zf2/blob/release-2.3.7/library/Zend/Http/PhpEnvironment/Request.php#L477-L575) - to the [logic in Symfony 2](https://github.com/symfony/symfony/blob/2.7/src/Symfony/Component/HttpFoundation/Request.php#L1858-L1877). -- Most implementations appear to allow manual injection of a base path to the - router and/or any facilities used for URI generation. -- The primary use cases — routing and URI generation — typically are the only - consumers of the functionality; developers usually do not need to be aware - of the base path concept as other objects take care of that detail for them. - As examples: - - A router will strip off the base path for you during routing; you do not - need to pass the modified path to the router. - - View helpers, template filters, etc. typically are injected with a base path - prior to invocation. Sometimes this is manually done, though more often it - is the result of framework wiring. -- All sources necessary for calculating the base path *are already in the - `RequestInterface` instance*, via server parameters and the URI instance. - -Our stance is that base path detection is framework and/or application -specific, and the results of detection can be easily injected into objects that -need it, and/or calculated as needed using utility functions and/or classes from -the `RequestInterface` instance itself. - -### Why does getUploadedFiles() return objects instead of arrays? - -`getUploadedFiles()` returns a tree of `Psr\Http\Message\UploadedFileInterface` -instances. This is done primarily to simplify specification: instead of -requiring paragraphs of implementation specification for an array, we specify an -interface. - -Additionally, the data in an `UploadedFileInterface` is normalized to work in -both SAPI and non-SAPI environments. This allows the creation of processes to parse -the message body manually and assign contents to streams without first writing -to the filesystem, while still allowing proper handling of file uploads in SAPI -environments. - -### What about "special" header values? - -A number of header values contain unique representation requirements which can -pose problems both for consumption as well as generation; in particular, cookies -and the `Accept` header. - -This proposal does not provide any special treatment of any header types. The -base `MessageInterface` provides methods for header retrieval and setting, and -all header values are, in the end, string values. - -Developers are encouraged to write commodity libraries for interacting with -these header values, either for the purposes of parsing or generation. Users may -then consume these libraries when needing to interact with those values. -Examples of this practice already exist in libraries such as -[willdurand/Negotiation](https://github.com/willdurand/Negotiation) and -[Aura.Accept](https://github.com/auraphp/Aura.Accept). So long as the object -has functionality for casting the value to a string, these objects can be -used to populate the headers of an HTTP message. - -## 6. People - -### 6.1 Editor(s) - -* Matthew Weier O'Phinney - -### 6.2 Sponsors - -* Paul M. Jones -* Beau Simensen (coordinator) - -### 6.3 Contributors - -* Michael Dowling -* Larry Garfield -* Evert Pot -* Tobias Schultze -* Bernhard Schussek -* Anton Serdyuk -* Phil Sturgeon -* Chris Wilkinson diff --git a/_docs/psr/psr-13.md b/_docs/psr/psr-13.md deleted file mode 100644 index be5a618..0000000 --- a/_docs/psr/psr-13.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: PRS-13 -category: PSRs -order: 8 ---- From 74ffc1c49b8148bc12930a718373b5032632baf8 Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Sun, 30 Jun 2019 02:20:37 -0300 Subject: [PATCH 02/11] file renamed --- ...c-coding-standard.md => PSR-1-padrao-basico-de-codificacao.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename _docs/psr/{PSR-1-basic-coding-standard.md => PSR-1-padrao-basico-de-codificacao.md} (100%) diff --git a/_docs/psr/PSR-1-basic-coding-standard.md b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md similarity index 100% rename from _docs/psr/PSR-1-basic-coding-standard.md rename to _docs/psr/PSR-1-padrao-basico-de-codificacao.md From 898ff852002e6b23672f120e53b6061dc587678f Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Sun, 30 Jun 2019 03:55:44 -0300 Subject: [PATCH 03/11] Fixed indent on PSR-1. Renamed PSR-2 and PSR-2-meta files. PSR-2-meta translated. Started PSR-2 translation --- .../psr/PSR-1-padrao-basico-de-codificacao.md | 3 +- _docs/psr/PSR-2-coding-style-guide-meta.md | 38 -------- .../psr/PSR-2-guia-estilo-codificacao-meta.md | 34 +++++++ ...de.md => PSR-2-guia-estilo-codificacao.md} | 92 +++++++++---------- 4 files changed, 82 insertions(+), 85 deletions(-) delete mode 100644 _docs/psr/PSR-2-coding-style-guide-meta.md create mode 100644 _docs/psr/PSR-2-guia-estilo-codificacao-meta.md rename _docs/psr/{PSR-2-coding-style-guide.md => PSR-2-guia-estilo-codificacao.md} (88%) diff --git a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md index 857aa4f..2d0a126 100644 --- a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md +++ b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md @@ -5,7 +5,8 @@ que são necessários para garantir um alto nível de interoperabilidade técnic compartilhados As palavras-chave "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", -"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" nesse documento devem ser interpretadas como descrito em [RFC 2119]. +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" nesse documento +devem ser interpretadas como descrito na [RFC 2119]. #### Tradução das Palavras-chave "MUST" (DEVE); diff --git a/_docs/psr/PSR-2-coding-style-guide-meta.md b/_docs/psr/PSR-2-coding-style-guide-meta.md deleted file mode 100644 index bd9e3ce..0000000 --- a/_docs/psr/PSR-2-coding-style-guide-meta.md +++ /dev/null @@ -1,38 +0,0 @@ -## 1. Summary - -The intent of this guide is to reduce cognitive friction when scanning code from different authors. It does so -by enumerating a shared set of rules and expectations about how to format PHP code. - -The style rules herein are derived from commonalities among the various member projects. When various authors -collaborate across multiple projects, it helps to have one set of guidelines to be used among all those -projects. Thus, the benefit of this guide is not in the rules themselves, but in the sharing of those rules. - -## 2. Votes - -- **Acceptance Vote:** [ML](https://groups.google.com/d/msg/php-fig/c-QVvnZdMQ0/TdDMdzKFpdIJ) - -## 3. Errata - -### 3.1 - Multi-line Arguments (09/08/2013) - -Using one or more multi-line arguments (i.e: arrays or anonymous functions) does not constitute -splitting the argument list itself, therefore Section 4.6 is not automatically enforced. Arrays and anonymous -functions are able to span multiple lines. - -The following examples are perfectly valid in PSR-2: - -~~~php -get('/hello/{name}', function ($name) use ($app) { - return 'Hello '.$app->escape($name); -}); -~~~ - -### 3.2 - Extending Multiple Interfaces (10/17/2013) - -When extending multiple interfaces, the list of `extends` should be treated the same as a list -of `implements`, as declared in Section 4.1. diff --git a/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md b/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md new file mode 100644 index 0000000..b65377f --- /dev/null +++ b/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md @@ -0,0 +1,34 @@ +## 1. Resumo + +A intenção deste guia é reduzir o atrito cognitivo ao escanear códigos de diferentes autores. Para isso, são enumerados um conjunto compartilhado de regras e expectativas sobre como formatar o código PHP + +As regras de estilo aqui são derivadas de semelhanças entre os vários projetos de membros. Quando vários autores colaboram em vários projetos, ajuda ter um conjunto de diretrizes a serem usadas entre todos esses projetos. Assim, o benefício deste guia não está nas próprias regras, mas no compartilhamento dessas regras. + +## 2. Votos + +- **Votação de Aceitação:** [ML](https://groups.google.com/d/msg/php-fig/c-QVvnZdMQ0/TdDMdzKFpdIJ) + +## 3. Errata + +### 3.1 - Argumentos de Várias Linhas (08/09/2013) + +O uso de um ou mais argumentos de várias linhas (ou seja, arrays ou funções anônimas) não constitui +a divisão da própria lista de argumentos, portanto, a Seção 4.6 não é aplicada automaticamente. +Matrizes e funções anônimas são capazes de abranger várias linhas. + +Os exemplos a seguir são perfeitamente válidos no PSR-2: + +~~~php +get('/hello/{name}', function ($name) use ($app) { + return 'Hello '.$app->escape($name); +}); +~~~ + +### 3.2 - Estendendo Múltiplas Interfaces (17/10/2013) +Ao estender várias interfaces, a lista de `extends` deve ser tratada da mesma forma que uma lista de `implements`, +conforme declarado na Seção 4.1. diff --git a/_docs/psr/PSR-2-coding-style-guide.md b/_docs/psr/PSR-2-guia-estilo-codificacao.md similarity index 88% rename from _docs/psr/PSR-2-coding-style-guide.md rename to _docs/psr/PSR-2-guia-estilo-codificacao.md index 2079afe..ac505a9 100644 --- a/_docs/psr/PSR-2-coding-style-guide.md +++ b/_docs/psr/PSR-2-guia-estilo-codificacao.md @@ -1,59 +1,59 @@ #Guia de Estilo de Codificação -This guide extends and expands on [PSR-1], the basic coding standard. +Este guia se estende e se expande no [PSR-1], o padrão básico de codificação. -The intent of this guide is to reduce cognitive friction when scanning code -from different authors. It does so by enumerating a shared set of rules and -expectations about how to format PHP code. +A intenção deste guia é reduzir o atrito cognitivo ao escanear códigos de +diferentes autores. Para isso, são enumerados um conjunto compartilhado +de regras e expectativas sobre como formatar o código PHP -The style rules herein are derived from commonalities among the various member -projects. When various authors collaborate across multiple projects, it helps -to have one set of guidelines to be used among all those projects. Thus, the -benefit of this guide is not in the rules themselves, but in the sharing of -those rules. +As regras de estilo aqui são derivadas de semelhanças entre os vários +projetos de membros. Quando vários autores colaboram em vários projetos, +ajuda ter um conjunto de diretrizes a serem usadas entre todos esses +projetos. Assim, o benefício deste guia não está nas próprias regras, +mas no compartilhamento dessas regras. -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 [RFC 2119]. +As palavras-chave "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" nesse documento +devem ser interpretadas como descrito na [RFC 2119]. [RFC 2119]: http://www.ietf.org/rfc/rfc2119.txt -[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md [PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md -## 1. Overview +## 1. Visão Geral -- Code MUST follow a "coding style guide" PSR [[PSR-1]]. +- O código DEVE seguir um PSR de "Guia de Estilo de Codificação" [[PSR-1]]. -- Code MUST use 4 spaces for indenting, not tabs. +- O código DEVE utilizar 4 espaços para indentação, não tabs. -- There MUST NOT be a hard limit on line length; the soft limit MUST be 120 - characters; lines SHOULD be 80 characters or less. +- NÃO DEVE haver um limite rígido no comprimento da linha; o limite suave + DEVE ter 120 caracteres; linhas devem ter 80 caracteres ou menos. -- There MUST be one blank line after the `namespace` declaration, and there - MUST be one blank line after the block of `use` declarations. +- Deve haver uma linha em branco após a declaração `namespace`, e DEVE + haver uma linha em branco após o bloco de declarações `use`. -- Opening braces for classes MUST go on the next line, and closing braces MUST - go on the next line after the body. +- A abertura de chaves para as classes DEVE ir na próxima linha, + e fechamento das chaves deve ir na próxima linha após o corpo. -- Opening braces for methods MUST go on the next line, and closing braces MUST - go on the next line after the body. +- A abertura de chaves para os métodos DEVE ser feita na próxima linha, + e o fechamento das chaves DEVE ser feito na próxima linha após o corpo. -- Visibility MUST be declared on all properties and methods; `abstract` and - `final` MUST be declared before the visibility; `static` MUST be declared - after the visibility. +- A visibilidade DEVE ser declarada em todas as propriedades e métodos; + `abstract` e `final` DEVEM ser declarados antes da visibilidade; + `static` DEVE ser declarado depois da visibilidade. -- Control structure keywords MUST have one space after them; method and - function calls MUST NOT. +- Palavras-chave da estrutura de controle DEVEM ter um espaço depois delas; + Chamadas de método e função NÃO DEVEM. -- Opening braces for control structures MUST go on the same line, and closing - braces MUST go on the next line after the body. +- A abertura de chaves para estruturas de controle DEVEM ir na mesma linha, + e o fechamento de chaves DEVE ser feito na linha após o corpo. -- Opening parentheses for control structures MUST NOT have a space after them, - and closing parentheses for control structures MUST NOT have a space before. +- A abertura de parênteses para estruturas de controle NÃO DEVE ter um espaço + depois deles, e o fechamento de parênteses para estruturas de controle + NÃO DEVE ter um espaço antes. -### 1.1. Example +### 1.1. Exemplo -This example encompasses some of the rules below as a quick overview: +Este exemplo engloba algumas das regras abaixo como uma visão geral rápida: ~~~php ` tag MUST be omitted from files containing only PHP. +A tag de fechamento `?>` DEVE ser omitida dos arquivos contendo apenas PHP. -### 2.3. Lines +### 2.3. Linhas There MUST NOT be a hard limit on line length. @@ -605,12 +605,12 @@ guide. These include but are not limited to: Future recommendations MAY revise and extend this guide to address those or other elements of style and practice. -## Appendix A. Survey +## Apêndice A. Pesquisa In writing this style guide, the group took a survey of member projects to determine common practices. The survey is retained herein for posterity. -### A.1. Survey Data +### A.1. Dados de Pesquisa url,http://www.horde.org/apps/horde/docs/CODING_STANDARDS,http://pear.php.net/manual/en/standards.php,http://solarphp.com/manual/appendix-standards.style,http://framework.zend.com/manual/en/coding-standard.html,http://symfony.com/doc/2.0/contributing/code/standards.html,http://www.ppi.io/docs/coding-standards.html,https://github.com/ezsystems/ezp-next/wiki/codingstandards,http://book.cakephp.org/2.0/en/contributing/cakephp-coding-conventions.html,https://github.com/UnionOfRAD/lithium/wiki/Spec%3A-Coding,http://drupal.org/coding-standards,http://code.google.com/p/sabredav/,http://area51.phpbb.com/docs/31x/coding-guidelines.html,https://docs.google.com/a/zikula.org/document/edit?authkey=CPCU0Us&hgd=1&id=1fcqb93Sn-hR9c0mkN6m_tyWnmEvoswKBtSc0tKkZmJA,http://www.chisimba.com,n/a,https://github.com/Respect/project-info/blob/master/coding-standards-sample.php,n/a,Object Calisthenics for PHP,http://doc.nette.org/en/coding-standard,http://flow3.typo3.org,https://github.com/propelorm/Propel2/wiki/Coding-Standards,http://developer.joomla.org/coding-standards.html voting,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,yes,no,no,no,?,yes,no,yes From 19592db3d154cad499edff171cc9d2841811f9fc Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Wed, 10 Jul 2019 08:27:18 -0300 Subject: [PATCH 04/11] fixed front matter --- _docs/psr/PSR-0(Descontinuada).md | 6 ++++++ _docs/psr/PSR-1-padrao-basico-de-codificacao.md | 6 ++++++ _docs/psr/PSR-11-container-meta.md | 6 ++++++ _docs/psr/PSR-11-container.md | 6 ++++++ _docs/psr/PSR-13-links-meta.md | 6 ++++++ _docs/psr/PSR-13-links.md | 6 ++++++ _docs/psr/PSR-14-event-dispatcher-meta.md | 6 ++++++ _docs/psr/PSR-14-event-dispatcher.md | 6 ++++++ _docs/psr/PSR-15-request-handlers-meta.md | 6 ++++++ _docs/psr/PSR-15-request-handlers.md | 6 ++++++ _docs/psr/PSR-16-simple-cache-meta.md | 6 ++++++ _docs/psr/PSR-16-simple-cache.md | 6 ++++++ _docs/psr/PSR-17-http-factory-meta.md | 6 ++++++ _docs/psr/PSR-17-http-factory.md | 6 ++++++ _docs/psr/PSR-18-http-client-meta.md | 6 ++++++ _docs/psr/PSR-18-http-client.md | 6 ++++++ _docs/psr/PSR-2-guia-estilo-codificacao-meta.md | 6 ++++++ _docs/psr/PSR-2-guia-estilo-codificacao.md | 6 ++++++ _docs/psr/PSR-3-logger-interface.md | 6 ++++++ _docs/psr/PSR-4-autoloader-examples.md | 6 ++++++ _docs/psr/PSR-4-autoloader-meta.md | 6 ++++++ _docs/psr/PSR-4-autoloader.md | 6 ++++++ _docs/psr/PSR-6-cache-meta.md | 6 ++++++ _docs/psr/PSR-6-cache.md | 6 ++++++ _docs/psr/PSR-7-http-message-meta.md | 6 ++++++ _docs/psr/PSR-7-http-message.md | 6 ++++++ 26 files changed, 156 insertions(+) diff --git a/_docs/psr/PSR-0(Descontinuada).md b/_docs/psr/PSR-0(Descontinuada).md index 5672bcc..7218fb7 100644 --- a/_docs/psr/PSR-0(Descontinuada).md +++ b/_docs/psr/PSR-0(Descontinuada).md @@ -1,3 +1,9 @@ +--- +title: PRS-0 +category: PSRs +order: 0 +--- + Padrão de Carregamento Automático (AutoLoading Standard) ==================== diff --git a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md index 2d0a126..30e612b 100644 --- a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md +++ b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md @@ -1,3 +1,9 @@ +--- +title: PRS-1 +category: PSRs +order: 1 +--- + # Normas Básicas de Codificação Nesta seção da norma, compreende-se o que deve ser considerado elementos básicos de codificação diff --git a/_docs/psr/PSR-11-container-meta.md b/_docs/psr/PSR-11-container-meta.md index 82c61e3..53690e3 100644 --- a/_docs/psr/PSR-11-container-meta.md +++ b/_docs/psr/PSR-11-container-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-11 +category: PSRs +order: 13 +--- + # Container Meta Document ## 1. Introduction diff --git a/_docs/psr/PSR-11-container.md b/_docs/psr/PSR-11-container.md index 0b51e2b..35f30b6 100644 --- a/_docs/psr/PSR-11-container.md +++ b/_docs/psr/PSR-11-container.md @@ -1,3 +1,9 @@ +--- +title: PRS-11 +category: PSRs +order: 12 +--- + # Container interface This document describes a common interface for dependency injection containers. diff --git a/_docs/psr/PSR-13-links-meta.md b/_docs/psr/PSR-13-links-meta.md index d096d28..bd08674 100644 --- a/_docs/psr/PSR-13-links-meta.md +++ b/_docs/psr/PSR-13-links-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-13 +category: PSRs +order: 15 +--- + # Link Definition Meta Document ## 1. Summary diff --git a/_docs/psr/PSR-13-links.md b/_docs/psr/PSR-13-links.md index 2cec7ff..4392661 100644 --- a/_docs/psr/PSR-13-links.md +++ b/_docs/psr/PSR-13-links.md @@ -1,3 +1,9 @@ +--- +title: PRS-13 +category: PSRs +order: 14 +--- + # Link definition interfaces Hypermedia links are becoming an increasingly important part of the web, in both HTML contexts diff --git a/_docs/psr/PSR-14-event-dispatcher-meta.md b/_docs/psr/PSR-14-event-dispatcher-meta.md index 9a2f6a9..d68a62e 100644 --- a/_docs/psr/PSR-14-event-dispatcher-meta.md +++ b/_docs/psr/PSR-14-event-dispatcher-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-14 +category: PSRs +order: 17 +--- + Event Dispatcher Meta Document ============================== diff --git a/_docs/psr/PSR-14-event-dispatcher.md b/_docs/psr/PSR-14-event-dispatcher.md index d91e081..46762e9 100644 --- a/_docs/psr/PSR-14-event-dispatcher.md +++ b/_docs/psr/PSR-14-event-dispatcher.md @@ -1,3 +1,9 @@ +--- +title: PRS-14 +category: PSRs +order: 16 +--- + Event Dispatcher ================ diff --git a/_docs/psr/PSR-15-request-handlers-meta.md b/_docs/psr/PSR-15-request-handlers-meta.md index 7ddddc6..0305622 100644 --- a/_docs/psr/PSR-15-request-handlers-meta.md +++ b/_docs/psr/PSR-15-request-handlers-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-15 +category: PSRs +order: 19 +--- + HTTP Server Request Handlers Meta Document ========================================== diff --git a/_docs/psr/PSR-15-request-handlers.md b/_docs/psr/PSR-15-request-handlers.md index 67d1a9c..206f509 100644 --- a/_docs/psr/PSR-15-request-handlers.md +++ b/_docs/psr/PSR-15-request-handlers.md @@ -1,3 +1,9 @@ +--- +title: PRS-15 +category: PSRs +order: 18 +--- + HTTP Server Request Handlers ============================ diff --git a/_docs/psr/PSR-16-simple-cache-meta.md b/_docs/psr/PSR-16-simple-cache-meta.md index 9eb37b6..f6b3844 100644 --- a/_docs/psr/PSR-16-simple-cache-meta.md +++ b/_docs/psr/PSR-16-simple-cache-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-16 +category: PSRs +order: 21 +--- + # PSR-16 Meta Document ## 1. Summary diff --git a/_docs/psr/PSR-16-simple-cache.md b/_docs/psr/PSR-16-simple-cache.md index 3308672..5d4d3ce 100644 --- a/_docs/psr/PSR-16-simple-cache.md +++ b/_docs/psr/PSR-16-simple-cache.md @@ -1,3 +1,9 @@ +--- +title: PRS-16 +category: PSRs +order: 20 +--- + Common Interface for Caching Libraries ====================================== diff --git a/_docs/psr/PSR-17-http-factory-meta.md b/_docs/psr/PSR-17-http-factory-meta.md index 97679e1..87ce918 100644 --- a/_docs/psr/PSR-17-http-factory-meta.md +++ b/_docs/psr/PSR-17-http-factory-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-17 +category: PSRs +order: 23 +--- + HTTP Factories Meta =================== diff --git a/_docs/psr/PSR-17-http-factory.md b/_docs/psr/PSR-17-http-factory.md index cf7b31c..4f33e00 100644 --- a/_docs/psr/PSR-17-http-factory.md +++ b/_docs/psr/PSR-17-http-factory.md @@ -1,3 +1,9 @@ +--- +title: PRS-17 +category: PSRs +order: 22 +--- + HTTP Factories ============== diff --git a/_docs/psr/PSR-18-http-client-meta.md b/_docs/psr/PSR-18-http-client-meta.md index 7daf73a..0deea2e 100644 --- a/_docs/psr/PSR-18-http-client-meta.md +++ b/_docs/psr/PSR-18-http-client-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-18 +category: PSRs +order: 25 +--- + HTTP Client Meta Document ========================= diff --git a/_docs/psr/PSR-18-http-client.md b/_docs/psr/PSR-18-http-client.md index af37997..af110ca 100644 --- a/_docs/psr/PSR-18-http-client.md +++ b/_docs/psr/PSR-18-http-client.md @@ -1,3 +1,9 @@ +--- +title: PRS-18 +category: PSRs +order: 24 +--- + HTTP Client =========== diff --git a/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md b/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md index b65377f..fd177dc 100644 --- a/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md +++ b/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-2 +category: PSRs +order: 3 +--- + ## 1. Resumo A intenção deste guia é reduzir o atrito cognitivo ao escanear códigos de diferentes autores. Para isso, são enumerados um conjunto compartilhado de regras e expectativas sobre como formatar o código PHP diff --git a/_docs/psr/PSR-2-guia-estilo-codificacao.md b/_docs/psr/PSR-2-guia-estilo-codificacao.md index ac505a9..eb3d81c 100644 --- a/_docs/psr/PSR-2-guia-estilo-codificacao.md +++ b/_docs/psr/PSR-2-guia-estilo-codificacao.md @@ -1,3 +1,9 @@ +--- +title: PRS-2 +category: PSRs +order: 2 +--- + #Guia de Estilo de Codificação Este guia se estende e se expande no [PSR-1], o padrão básico de codificação. diff --git a/_docs/psr/PSR-3-logger-interface.md b/_docs/psr/PSR-3-logger-interface.md index 1124e9f..35cbcef 100644 --- a/_docs/psr/PSR-3-logger-interface.md +++ b/_docs/psr/PSR-3-logger-interface.md @@ -1,3 +1,9 @@ +--- +title: PRS-3 +category: PSRs +order: 4 +--- + Logger Interface ================ diff --git a/_docs/psr/PSR-4-autoloader-examples.md b/_docs/psr/PSR-4-autoloader-examples.md index 3481846..b15fad9 100644 --- a/_docs/psr/PSR-4-autoloader-examples.md +++ b/_docs/psr/PSR-4-autoloader-examples.md @@ -1,3 +1,9 @@ +--- +title: PRS-4 +category: PSRs +order: 6 +--- + Example Implementations of PSR-4 ================================ diff --git a/_docs/psr/PSR-4-autoloader-meta.md b/_docs/psr/PSR-4-autoloader-meta.md index b01495d..cd5c357 100644 --- a/_docs/psr/PSR-4-autoloader-meta.md +++ b/_docs/psr/PSR-4-autoloader-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-4 +category: PSRs +order: 7 +--- + # PSR-4 Meta Document ## 1. Summary diff --git a/_docs/psr/PSR-4-autoloader.md b/_docs/psr/PSR-4-autoloader.md index 6514c23..5685848 100644 --- a/_docs/psr/PSR-4-autoloader.md +++ b/_docs/psr/PSR-4-autoloader.md @@ -1,3 +1,9 @@ +--- +title: PRS-4 +category: PSRs +order: 5 +--- + # Autoloader The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", diff --git a/_docs/psr/PSR-6-cache-meta.md b/_docs/psr/PSR-6-cache-meta.md index 220d1fb..4113499 100644 --- a/_docs/psr/PSR-6-cache-meta.md +++ b/_docs/psr/PSR-6-cache-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-6 +category: PSRs +order: 9 +--- + # PSR-Cache Meta Document ## 1. Summary diff --git a/_docs/psr/PSR-6-cache.md b/_docs/psr/PSR-6-cache.md index d245390..1b87e84 100644 --- a/_docs/psr/PSR-6-cache.md +++ b/_docs/psr/PSR-6-cache.md @@ -1,3 +1,9 @@ +--- +title: PRS-6 +category: PSRs +order: 8 +--- + # Caching Interface Caching is a common way to improve the performance of any project, making diff --git a/_docs/psr/PSR-7-http-message-meta.md b/_docs/psr/PSR-7-http-message-meta.md index 4b8a5bc..92b4d5e 100644 --- a/_docs/psr/PSR-7-http-message-meta.md +++ b/_docs/psr/PSR-7-http-message-meta.md @@ -1,3 +1,9 @@ +--- +title: PRS-7 +category: PSRs +order: 11 +--- + # HTTP Message Meta Document ## 1. Summary diff --git a/_docs/psr/PSR-7-http-message.md b/_docs/psr/PSR-7-http-message.md index 419f7de..eda3f80 100644 --- a/_docs/psr/PSR-7-http-message.md +++ b/_docs/psr/PSR-7-http-message.md @@ -1,3 +1,9 @@ +--- +title: PRS-7 +category: PSRs +order: 10 +--- + # HTTP message interfaces This document describes common interfaces for representing HTTP messages as From b7e113de12259a6d58561972e9c8ec1f4a13e9d2 Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Wed, 10 Jul 2019 11:09:34 -0300 Subject: [PATCH 05/11] fixed PRS typo to -> PSR --- _docs/psr/PSR-0(Descontinuada).md | 2 +- _docs/psr/PSR-1-padrao-basico-de-codificacao.md | 2 +- _docs/psr/PSR-11-container-meta.md | 2 +- _docs/psr/PSR-11-container.md | 2 +- _docs/psr/PSR-13-links-meta.md | 2 +- _docs/psr/PSR-13-links.md | 2 +- _docs/psr/PSR-14-event-dispatcher-meta.md | 2 +- _docs/psr/PSR-14-event-dispatcher.md | 2 +- _docs/psr/PSR-15-request-handlers-meta.md | 2 +- _docs/psr/PSR-15-request-handlers.md | 2 +- _docs/psr/PSR-16-simple-cache-meta.md | 2 +- _docs/psr/PSR-16-simple-cache.md | 2 +- _docs/psr/PSR-17-http-factory-meta.md | 2 +- _docs/psr/PSR-17-http-factory.md | 2 +- _docs/psr/PSR-18-http-client-meta.md | 2 +- _docs/psr/PSR-18-http-client.md | 2 +- _docs/psr/PSR-2-guia-estilo-codificacao-meta.md | 2 +- _docs/psr/PSR-2-guia-estilo-codificacao.md | 2 +- _docs/psr/PSR-3-logger-interface.md | 2 +- _docs/psr/PSR-4-autoloader-examples.md | 2 +- _docs/psr/PSR-4-autoloader-meta.md | 2 +- _docs/psr/PSR-4-autoloader.md | 2 +- _docs/psr/PSR-6-cache-meta.md | 2 +- _docs/psr/PSR-6-cache.md | 2 +- _docs/psr/PSR-7-http-message-meta.md | 2 +- _docs/psr/PSR-7-http-message.md | 2 +- 26 files changed, 26 insertions(+), 26 deletions(-) diff --git a/_docs/psr/PSR-0(Descontinuada).md b/_docs/psr/PSR-0(Descontinuada).md index 7218fb7..c004214 100644 --- a/_docs/psr/PSR-0(Descontinuada).md +++ b/_docs/psr/PSR-0(Descontinuada).md @@ -1,5 +1,5 @@ --- -title: PRS-0 +title: PSR-0 category: PSRs order: 0 --- diff --git a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md index 30e612b..50d1cd6 100644 --- a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md +++ b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md @@ -1,5 +1,5 @@ --- -title: PRS-1 +title: PSR-1 category: PSRs order: 1 --- diff --git a/_docs/psr/PSR-11-container-meta.md b/_docs/psr/PSR-11-container-meta.md index 53690e3..009065c 100644 --- a/_docs/psr/PSR-11-container-meta.md +++ b/_docs/psr/PSR-11-container-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-11 +title: PSR-11 category: PSRs order: 13 --- diff --git a/_docs/psr/PSR-11-container.md b/_docs/psr/PSR-11-container.md index 35f30b6..fed6651 100644 --- a/_docs/psr/PSR-11-container.md +++ b/_docs/psr/PSR-11-container.md @@ -1,5 +1,5 @@ --- -title: PRS-11 +title: PSR-11 category: PSRs order: 12 --- diff --git a/_docs/psr/PSR-13-links-meta.md b/_docs/psr/PSR-13-links-meta.md index bd08674..236f097 100644 --- a/_docs/psr/PSR-13-links-meta.md +++ b/_docs/psr/PSR-13-links-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-13 +title: PSR-13 category: PSRs order: 15 --- diff --git a/_docs/psr/PSR-13-links.md b/_docs/psr/PSR-13-links.md index 4392661..40833c1 100644 --- a/_docs/psr/PSR-13-links.md +++ b/_docs/psr/PSR-13-links.md @@ -1,5 +1,5 @@ --- -title: PRS-13 +title: PSR-13 category: PSRs order: 14 --- diff --git a/_docs/psr/PSR-14-event-dispatcher-meta.md b/_docs/psr/PSR-14-event-dispatcher-meta.md index d68a62e..8834ed8 100644 --- a/_docs/psr/PSR-14-event-dispatcher-meta.md +++ b/_docs/psr/PSR-14-event-dispatcher-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-14 +title: PSR-14 category: PSRs order: 17 --- diff --git a/_docs/psr/PSR-14-event-dispatcher.md b/_docs/psr/PSR-14-event-dispatcher.md index 46762e9..88200ec 100644 --- a/_docs/psr/PSR-14-event-dispatcher.md +++ b/_docs/psr/PSR-14-event-dispatcher.md @@ -1,5 +1,5 @@ --- -title: PRS-14 +title: PSR-14 category: PSRs order: 16 --- diff --git a/_docs/psr/PSR-15-request-handlers-meta.md b/_docs/psr/PSR-15-request-handlers-meta.md index 0305622..23daf2a 100644 --- a/_docs/psr/PSR-15-request-handlers-meta.md +++ b/_docs/psr/PSR-15-request-handlers-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-15 +title: PSR-15 category: PSRs order: 19 --- diff --git a/_docs/psr/PSR-15-request-handlers.md b/_docs/psr/PSR-15-request-handlers.md index 206f509..cef45b9 100644 --- a/_docs/psr/PSR-15-request-handlers.md +++ b/_docs/psr/PSR-15-request-handlers.md @@ -1,5 +1,5 @@ --- -title: PRS-15 +title: PSR-15 category: PSRs order: 18 --- diff --git a/_docs/psr/PSR-16-simple-cache-meta.md b/_docs/psr/PSR-16-simple-cache-meta.md index f6b3844..496fcdb 100644 --- a/_docs/psr/PSR-16-simple-cache-meta.md +++ b/_docs/psr/PSR-16-simple-cache-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-16 +title: PSR-16 category: PSRs order: 21 --- diff --git a/_docs/psr/PSR-16-simple-cache.md b/_docs/psr/PSR-16-simple-cache.md index 5d4d3ce..3c61c0e 100644 --- a/_docs/psr/PSR-16-simple-cache.md +++ b/_docs/psr/PSR-16-simple-cache.md @@ -1,5 +1,5 @@ --- -title: PRS-16 +title: PSR-16 category: PSRs order: 20 --- diff --git a/_docs/psr/PSR-17-http-factory-meta.md b/_docs/psr/PSR-17-http-factory-meta.md index 87ce918..f8b115f 100644 --- a/_docs/psr/PSR-17-http-factory-meta.md +++ b/_docs/psr/PSR-17-http-factory-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-17 +title: PSR-17 category: PSRs order: 23 --- diff --git a/_docs/psr/PSR-17-http-factory.md b/_docs/psr/PSR-17-http-factory.md index 4f33e00..eb647f5 100644 --- a/_docs/psr/PSR-17-http-factory.md +++ b/_docs/psr/PSR-17-http-factory.md @@ -1,5 +1,5 @@ --- -title: PRS-17 +title: PSR-17 category: PSRs order: 22 --- diff --git a/_docs/psr/PSR-18-http-client-meta.md b/_docs/psr/PSR-18-http-client-meta.md index 0deea2e..aaec2b5 100644 --- a/_docs/psr/PSR-18-http-client-meta.md +++ b/_docs/psr/PSR-18-http-client-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-18 +title: PSR-18 category: PSRs order: 25 --- diff --git a/_docs/psr/PSR-18-http-client.md b/_docs/psr/PSR-18-http-client.md index af110ca..e1ff346 100644 --- a/_docs/psr/PSR-18-http-client.md +++ b/_docs/psr/PSR-18-http-client.md @@ -1,5 +1,5 @@ --- -title: PRS-18 +title: PSR-18 category: PSRs order: 24 --- diff --git a/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md b/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md index fd177dc..f92161d 100644 --- a/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md +++ b/_docs/psr/PSR-2-guia-estilo-codificacao-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-2 +title: PSR-2 category: PSRs order: 3 --- diff --git a/_docs/psr/PSR-2-guia-estilo-codificacao.md b/_docs/psr/PSR-2-guia-estilo-codificacao.md index eb3d81c..f31d788 100644 --- a/_docs/psr/PSR-2-guia-estilo-codificacao.md +++ b/_docs/psr/PSR-2-guia-estilo-codificacao.md @@ -1,5 +1,5 @@ --- -title: PRS-2 +title: PSR-2 category: PSRs order: 2 --- diff --git a/_docs/psr/PSR-3-logger-interface.md b/_docs/psr/PSR-3-logger-interface.md index 35cbcef..9896c61 100644 --- a/_docs/psr/PSR-3-logger-interface.md +++ b/_docs/psr/PSR-3-logger-interface.md @@ -1,5 +1,5 @@ --- -title: PRS-3 +title: PSR-3 category: PSRs order: 4 --- diff --git a/_docs/psr/PSR-4-autoloader-examples.md b/_docs/psr/PSR-4-autoloader-examples.md index b15fad9..16143df 100644 --- a/_docs/psr/PSR-4-autoloader-examples.md +++ b/_docs/psr/PSR-4-autoloader-examples.md @@ -1,5 +1,5 @@ --- -title: PRS-4 +title: PSR-4 category: PSRs order: 6 --- diff --git a/_docs/psr/PSR-4-autoloader-meta.md b/_docs/psr/PSR-4-autoloader-meta.md index cd5c357..f5868c4 100644 --- a/_docs/psr/PSR-4-autoloader-meta.md +++ b/_docs/psr/PSR-4-autoloader-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-4 +title: PSR-4 category: PSRs order: 7 --- diff --git a/_docs/psr/PSR-4-autoloader.md b/_docs/psr/PSR-4-autoloader.md index 5685848..83b4901 100644 --- a/_docs/psr/PSR-4-autoloader.md +++ b/_docs/psr/PSR-4-autoloader.md @@ -1,5 +1,5 @@ --- -title: PRS-4 +title: PSR-4 category: PSRs order: 5 --- diff --git a/_docs/psr/PSR-6-cache-meta.md b/_docs/psr/PSR-6-cache-meta.md index 4113499..0c723b3 100644 --- a/_docs/psr/PSR-6-cache-meta.md +++ b/_docs/psr/PSR-6-cache-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-6 +title: PSR-6 category: PSRs order: 9 --- diff --git a/_docs/psr/PSR-6-cache.md b/_docs/psr/PSR-6-cache.md index 1b87e84..9d8eb0a 100644 --- a/_docs/psr/PSR-6-cache.md +++ b/_docs/psr/PSR-6-cache.md @@ -1,5 +1,5 @@ --- -title: PRS-6 +title: PSR-6 category: PSRs order: 8 --- diff --git a/_docs/psr/PSR-7-http-message-meta.md b/_docs/psr/PSR-7-http-message-meta.md index 92b4d5e..03fea2b 100644 --- a/_docs/psr/PSR-7-http-message-meta.md +++ b/_docs/psr/PSR-7-http-message-meta.md @@ -1,5 +1,5 @@ --- -title: PRS-7 +title: PSR-7 category: PSRs order: 11 --- diff --git a/_docs/psr/PSR-7-http-message.md b/_docs/psr/PSR-7-http-message.md index eda3f80..cf7d51c 100644 --- a/_docs/psr/PSR-7-http-message.md +++ b/_docs/psr/PSR-7-http-message.md @@ -1,5 +1,5 @@ --- -title: PRS-7 +title: PSR-7 category: PSRs order: 10 --- From fa04633cd1b2892e0cada9c0a5a45fc53854af8c Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Wed, 10 Jul 2019 11:59:41 -0300 Subject: [PATCH 06/11] Removed all .DS_Store files and add .DS_Store to gitignore. Add some title translations. --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 1 + _docs/.DS_Store | Bin 6148 -> 0 bytes _docs/psr/.DS_Store | Bin 6148 -> 0 bytes _docs/psr/PSR-0(Descontinuada).md | 2 +- _docs/psr/PSR-1-padrao-basico-de-codificacao.md | 2 +- _docs/psr/PSR-2-guia-estilo-codificacao-meta.md | 2 +- _docs/psr/PSR-2-guia-estilo-codificacao.md | 2 +- _docs/psr/PSR-3-logger-interface.md | 2 +- 9 files changed, 6 insertions(+), 5 deletions(-) delete mode 100644 .DS_Store delete mode 100644 _docs/.DS_Store delete mode 100644 _docs/psr/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index bc26a8179add0181674e87f30f7ccc5078077989..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}N6?5Kh{vX+`Wou*Y1y_0Y2ZoP?#;gEwJC4=Q!nEq0-9q`S3fUD?;rH}VO5 z9cPlXv{b>9h|a*|n@naB^6ipI7-PIO44aHq8Djzzu~3HQ6TxxR1u0k$BG+>y!6>;4 z`YKq6CCBe%0KeT5>#&e1cFktL-&=6kkCL>}c;|&;X=!;yh>EDJRW7}r8hNRo4wIHY zILF?xpY{T4pD5Lz+J0~vbw{1*#(|1cKZ?5pog9T-2)Q_m;!urRY8Z!!p2sr-LX<_h zQ>~51j8Ma=f?KsLO3^J) zy+Pbp@eOz<8IwptVt^PR2L1^H_V^R4|75?kO=5r;_&x)8K1fhR*J5r^A05!(^%2KQ zh$vv=TLMv9bS>rvVFZMmR6vu;?GuBWbnr_X=UU7SnsmnX$}o>zncEi%*QTt$g zgVYiO#K1fQMboWf{XhKr{Xd^XJz{_u_)`qdAb3FNBA{uYh8Xx!20j34^HB@{ diff --git a/.gitignore b/.gitignore index f3a70a2..5e22474 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ _site/ vendor/ .bundle .directory +.ds_store \ No newline at end of file diff --git a/_docs/.DS_Store b/_docs/.DS_Store deleted file mode 100644 index 5c18195b9017b115cb9419c15b4121f6babdfcf8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z-O8ZYyFBf<5lVTMsQ!dlEvd2X8_|4=Qa!iVf7HB&kJXC9k1xb*8#u1%*HHbi9h}N{i86=TCI0pDp%IlH-xB(+E(qx9mZ2P^Rh|mc*zx7XI?h+ zjeZ`-qfg!QFT%mJSKm2~qs$AVL86kwU;rW4mthpdQzxE8L8|6)wL^%isP^iOJh!Za zrnIcqtSR$Or`44E*5Pbc6}x-wqtpJ~!(;w5dw$XUa-d(yw!t~Pf?~?McavxoN4GFC zkDf;n5(C5lF+dEg6a(fM5SuGiH5E$?5CcD90QUz84be7OXjEGVba;J6e+3Z*bbL!7 zN`tn+LL+!UxK0JssoXpFI=q-<5Gn)Zfm5T7$61~ z87OPBj_3ag{4z@)`HLxJ5d*})KVyJbx^CBjqRiR)tvozyCA2;?6pSlS0ResC5&#D7 gBMs%$eu+B7*#--ZI17%ebU?ZYC_<H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 Date: Wed, 10 Jul 2019 12:11:54 -0300 Subject: [PATCH 07/11] Change fixed title name --- _docs/psr/PSR-0(Descontinuada).md | 2 +- _docs/psr/PSR-1-padrao-basico-de-codificacao.md | 2 +- _docs/psr/PSR-11-container-meta.md | 2 +- _docs/psr/PSR-11-container.md | 2 +- _docs/psr/PSR-13-links-meta.md | 2 +- _docs/psr/PSR-13-links.md | 2 +- _docs/psr/PSR-14-event-dispatcher-meta.md | 2 +- _docs/psr/PSR-14-event-dispatcher.md | 2 +- _docs/psr/PSR-15-request-handlers-meta.md | 2 +- _docs/psr/PSR-15-request-handlers.md | 2 +- _docs/psr/PSR-16-simple-cache-meta.md | 2 +- _docs/psr/PSR-16-simple-cache.md | 2 +- _docs/psr/PSR-17-http-factory-meta.md | 2 +- _docs/psr/PSR-17-http-factory.md | 2 +- _docs/psr/PSR-18-http-client-meta.md | 2 +- _docs/psr/PSR-18-http-client.md | 2 +- _docs/psr/PSR-2-guia-estilo-codificacao.md | 2 +- _docs/psr/PSR-3-logger-interface.md | 2 +- _docs/psr/PSR-4-autoloader-examples.md | 2 +- _docs/psr/PSR-4-autoloader-meta.md | 2 +- _docs/psr/PSR-4-autoloader.md | 2 +- _docs/psr/PSR-6-cache-meta.md | 2 +- _docs/psr/PSR-6-cache.md | 2 +- _docs/psr/PSR-7-http-message-meta.md | 2 +- _docs/psr/PSR-7-http-message.md | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/_docs/psr/PSR-0(Descontinuada).md b/_docs/psr/PSR-0(Descontinuada).md index 979aed8..725ca3d 100644 --- a/_docs/psr/PSR-0(Descontinuada).md +++ b/_docs/psr/PSR-0(Descontinuada).md @@ -1,5 +1,5 @@ --- -title: PSR-0: Descontinuada +title: PSR-0 Descontinuada category: PSRs order: 0 --- diff --git a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md index e0dd47d..b5244b4 100644 --- a/_docs/psr/PSR-1-padrao-basico-de-codificacao.md +++ b/_docs/psr/PSR-1-padrao-basico-de-codificacao.md @@ -1,5 +1,5 @@ --- -title: PSR-1: Padrão Básico de Codificação +title: PSR-1 Padrão Básico de Codificação category: PSRs order: 1 --- diff --git a/_docs/psr/PSR-11-container-meta.md b/_docs/psr/PSR-11-container-meta.md index 009065c..76fb34f 100644 --- a/_docs/psr/PSR-11-container-meta.md +++ b/_docs/psr/PSR-11-container-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-11 +title: PSR-11 Meta Document category: PSRs order: 13 --- diff --git a/_docs/psr/PSR-11-container.md b/_docs/psr/PSR-11-container.md index fed6651..8d2267c 100644 --- a/_docs/psr/PSR-11-container.md +++ b/_docs/psr/PSR-11-container.md @@ -1,5 +1,5 @@ --- -title: PSR-11 +title: PSR-11 Container category: PSRs order: 12 --- diff --git a/_docs/psr/PSR-13-links-meta.md b/_docs/psr/PSR-13-links-meta.md index 236f097..9c2c3ad 100644 --- a/_docs/psr/PSR-13-links-meta.md +++ b/_docs/psr/PSR-13-links-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-13 +title: PSR-13 Meta Document category: PSRs order: 15 --- diff --git a/_docs/psr/PSR-13-links.md b/_docs/psr/PSR-13-links.md index 40833c1..1f88af0 100644 --- a/_docs/psr/PSR-13-links.md +++ b/_docs/psr/PSR-13-links.md @@ -1,5 +1,5 @@ --- -title: PSR-13 +title: PSR-13 Links category: PSRs order: 14 --- diff --git a/_docs/psr/PSR-14-event-dispatcher-meta.md b/_docs/psr/PSR-14-event-dispatcher-meta.md index 8834ed8..22d5a20 100644 --- a/_docs/psr/PSR-14-event-dispatcher-meta.md +++ b/_docs/psr/PSR-14-event-dispatcher-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-14 +title: PSR-14 Meta Document category: PSRs order: 17 --- diff --git a/_docs/psr/PSR-14-event-dispatcher.md b/_docs/psr/PSR-14-event-dispatcher.md index 88200ec..186c087 100644 --- a/_docs/psr/PSR-14-event-dispatcher.md +++ b/_docs/psr/PSR-14-event-dispatcher.md @@ -1,5 +1,5 @@ --- -title: PSR-14 +title: PSR-14 Expedição de Eventos category: PSRs order: 16 --- diff --git a/_docs/psr/PSR-15-request-handlers-meta.md b/_docs/psr/PSR-15-request-handlers-meta.md index 23daf2a..ea5f003 100644 --- a/_docs/psr/PSR-15-request-handlers-meta.md +++ b/_docs/psr/PSR-15-request-handlers-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-15 +title: PSR-15 Meta Document category: PSRs order: 19 --- diff --git a/_docs/psr/PSR-15-request-handlers.md b/_docs/psr/PSR-15-request-handlers.md index cef45b9..cf03b07 100644 --- a/_docs/psr/PSR-15-request-handlers.md +++ b/_docs/psr/PSR-15-request-handlers.md @@ -1,5 +1,5 @@ --- -title: PSR-15 +title: PSR-15 Manipulador de Requests category: PSRs order: 18 --- diff --git a/_docs/psr/PSR-16-simple-cache-meta.md b/_docs/psr/PSR-16-simple-cache-meta.md index 496fcdb..0b6be3e 100644 --- a/_docs/psr/PSR-16-simple-cache-meta.md +++ b/_docs/psr/PSR-16-simple-cache-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-16 +title: PSR-16 Meta Document category: PSRs order: 21 --- diff --git a/_docs/psr/PSR-16-simple-cache.md b/_docs/psr/PSR-16-simple-cache.md index 3c61c0e..cd9b409 100644 --- a/_docs/psr/PSR-16-simple-cache.md +++ b/_docs/psr/PSR-16-simple-cache.md @@ -1,5 +1,5 @@ --- -title: PSR-16 +title: PSR-16 Cache Simples category: PSRs order: 20 --- diff --git a/_docs/psr/PSR-17-http-factory-meta.md b/_docs/psr/PSR-17-http-factory-meta.md index f8b115f..c09f0ed 100644 --- a/_docs/psr/PSR-17-http-factory-meta.md +++ b/_docs/psr/PSR-17-http-factory-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-17 +title: PSR-17 Meta Document category: PSRs order: 23 --- diff --git a/_docs/psr/PSR-17-http-factory.md b/_docs/psr/PSR-17-http-factory.md index eb647f5..7c7a6b8 100644 --- a/_docs/psr/PSR-17-http-factory.md +++ b/_docs/psr/PSR-17-http-factory.md @@ -1,5 +1,5 @@ --- -title: PSR-17 +title: PSR-17 HTTP Factory category: PSRs order: 22 --- diff --git a/_docs/psr/PSR-18-http-client-meta.md b/_docs/psr/PSR-18-http-client-meta.md index aaec2b5..9be7966 100644 --- a/_docs/psr/PSR-18-http-client-meta.md +++ b/_docs/psr/PSR-18-http-client-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-18 +title: PSR-18 Meta Document category: PSRs order: 25 --- diff --git a/_docs/psr/PSR-18-http-client.md b/_docs/psr/PSR-18-http-client.md index e1ff346..b3eae8d 100644 --- a/_docs/psr/PSR-18-http-client.md +++ b/_docs/psr/PSR-18-http-client.md @@ -1,5 +1,5 @@ --- -title: PSR-18 +title: PSR-18 Client HTTP category: PSRs order: 24 --- diff --git a/_docs/psr/PSR-2-guia-estilo-codificacao.md b/_docs/psr/PSR-2-guia-estilo-codificacao.md index f313889..4769254 100644 --- a/_docs/psr/PSR-2-guia-estilo-codificacao.md +++ b/_docs/psr/PSR-2-guia-estilo-codificacao.md @@ -1,5 +1,5 @@ --- -title: PSR-2: Guia de Estilo de Codificação +title: PSR-2 Guia de Estilo de Codificação category: PSRs order: 2 --- diff --git a/_docs/psr/PSR-3-logger-interface.md b/_docs/psr/PSR-3-logger-interface.md index c83f6df..49bfa5b 100644 --- a/_docs/psr/PSR-3-logger-interface.md +++ b/_docs/psr/PSR-3-logger-interface.md @@ -1,5 +1,5 @@ --- -title: PSR-3: Interface de Log +title: PSR-3 Interface de Log category: PSRs order: 4 --- diff --git a/_docs/psr/PSR-4-autoloader-examples.md b/_docs/psr/PSR-4-autoloader-examples.md index 16143df..ca70d64 100644 --- a/_docs/psr/PSR-4-autoloader-examples.md +++ b/_docs/psr/PSR-4-autoloader-examples.md @@ -1,5 +1,5 @@ --- -title: PSR-4 +title: PSR-4 Exemplos de Autoloader category: PSRs order: 6 --- diff --git a/_docs/psr/PSR-4-autoloader-meta.md b/_docs/psr/PSR-4-autoloader-meta.md index f5868c4..b0c065f 100644 --- a/_docs/psr/PSR-4-autoloader-meta.md +++ b/_docs/psr/PSR-4-autoloader-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-4 +title: PSR-4 Meta Document category: PSRs order: 7 --- diff --git a/_docs/psr/PSR-4-autoloader.md b/_docs/psr/PSR-4-autoloader.md index 83b4901..5fd02c1 100644 --- a/_docs/psr/PSR-4-autoloader.md +++ b/_docs/psr/PSR-4-autoloader.md @@ -1,5 +1,5 @@ --- -title: PSR-4 +title: PSR-4: Autoloader category: PSRs order: 5 --- diff --git a/_docs/psr/PSR-6-cache-meta.md b/_docs/psr/PSR-6-cache-meta.md index 0c723b3..da2de99 100644 --- a/_docs/psr/PSR-6-cache-meta.md +++ b/_docs/psr/PSR-6-cache-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-6 +title: PSR-6 Meta Document category: PSRs order: 9 --- diff --git a/_docs/psr/PSR-6-cache.md b/_docs/psr/PSR-6-cache.md index 9d8eb0a..ce3057a 100644 --- a/_docs/psr/PSR-6-cache.md +++ b/_docs/psr/PSR-6-cache.md @@ -1,5 +1,5 @@ --- -title: PSR-6 +title: PSR-6 Cache category: PSRs order: 8 --- diff --git a/_docs/psr/PSR-7-http-message-meta.md b/_docs/psr/PSR-7-http-message-meta.md index 03fea2b..ba58e6b 100644 --- a/_docs/psr/PSR-7-http-message-meta.md +++ b/_docs/psr/PSR-7-http-message-meta.md @@ -1,5 +1,5 @@ --- -title: PSR-7 +title: PSR-7 Meta Document category: PSRs order: 11 --- diff --git a/_docs/psr/PSR-7-http-message.md b/_docs/psr/PSR-7-http-message.md index cf7d51c..4b716f6 100644 --- a/_docs/psr/PSR-7-http-message.md +++ b/_docs/psr/PSR-7-http-message.md @@ -1,5 +1,5 @@ --- -title: PSR-7 +title: PSR-7 Mensagens HTTP category: PSRs order: 10 --- From 5dc0d9dc2deb3fd19732fa2bda9fc962f3afe0af Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Wed, 10 Jul 2019 14:19:19 -0300 Subject: [PATCH 08/11] fixed title PSR4 --- _docs/psr/PSR-4-autoloader.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_docs/psr/PSR-4-autoloader.md b/_docs/psr/PSR-4-autoloader.md index 5fd02c1..03df06f 100644 --- a/_docs/psr/PSR-4-autoloader.md +++ b/_docs/psr/PSR-4-autoloader.md @@ -1,5 +1,5 @@ --- -title: PSR-4: Autoloader +title: PSR-4 Autoloader category: PSRs order: 5 --- From 2089f49158b3817598702286818d6683a1b846af Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Wed, 10 Jul 2019 21:16:50 -0300 Subject: [PATCH 09/11] Fixed typo in PSR18 and a gramatical mistake in PSR0 --- _docs/psr/PSR-0(Descontinuada).md | 2 +- _docs/psr/PSR-18-http-client.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_docs/psr/PSR-0(Descontinuada).md b/_docs/psr/PSR-0(Descontinuada).md index 725ca3d..0241af8 100644 --- a/_docs/psr/PSR-0(Descontinuada).md +++ b/_docs/psr/PSR-0(Descontinuada).md @@ -7,7 +7,7 @@ order: 0 Padrão de Carregamento Automático (AutoLoading Standard) ==================== -> **Obsoleto** - A partir de 21-10-2014, o PSR-0 foi marcado como obsoleto. [PSR-4] agora é recomendado +> **Obsoleto** - A partir de 21-10-2014, o PSR-0 foi marcado como obsoleto. Agora o [PSR-4] é recomendado como uma alternativa. [PSR-4]: http://www.php-fig.org/psr/psr-4/ diff --git a/_docs/psr/PSR-18-http-client.md b/_docs/psr/PSR-18-http-client.md index b3eae8d..9226d9e 100644 --- a/_docs/psr/PSR-18-http-client.md +++ b/_docs/psr/PSR-18-http-client.md @@ -1,5 +1,5 @@ --- -title: PSR-18 Client HTTP +title: PSR-18 Cliente HTTP category: PSRs order: 24 --- From 3fbcc9716082474ad552d40584755099abfa8c3c Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Thu, 11 Jul 2019 10:27:04 -0300 Subject: [PATCH 10/11] PSR-3 translated --- _docs/psr/PSR-3-logger-interface.md | 240 ++++++++++++++-------------- 1 file changed, 121 insertions(+), 119 deletions(-) diff --git a/_docs/psr/PSR-3-logger-interface.md b/_docs/psr/PSR-3-logger-interface.md index 49bfa5b..754c0bb 100644 --- a/_docs/psr/PSR-3-logger-interface.md +++ b/_docs/psr/PSR-3-logger-interface.md @@ -4,146 +4,147 @@ category: PSRs order: 4 --- -Logger Interface +Interface de Log ================ -This document describes a common interface for logging libraries. +Este documento descreve uma interface comum para registrar bibliotecas. -The main goal is to allow libraries to receive a `Psr\Log\LoggerInterface` -object and write logs to it in a simple and universal way. Frameworks -and CMSs that have custom needs MAY extend the interface for their own -purpose, but SHOULD remain compatible with this document. This ensures -that the third-party libraries an application uses can write to the -centralized application logs. +O objetivo principal é permitir que bibliotecas recebam o objeto `Psr\Log\LoggerInterface` +e gravem logs nesta, de maneira simples e universal. Frameworks e CMSs(sigla para +Content Manage Systems - Sistemas de Gerenciamento de Conteúdo) que têm necessidades +personalizadas PODEM estender a interface para suas próprias finalidades, mas DEVEM permanecer +compatíveis com este documento. Isso garante que as bibliotecas de terceiros que um aplicativo +utiliza, possam gravar nos logs de aplicativos centralizados. -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 [RFC 2119][]. +As palavras-chave "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" nesse documento devem ser +interpretadas como descrito na [RFC 2119][]. -The word `implementor` in this document is to be interpreted as someone -implementing the `LoggerInterface` in a log-related library or framework. -Users of loggers are referred to as `user`. +A palavra `implementador` nesse documento deve ser interpretada como alguém +implementando o `LoggerInterface` em uma biblioteca ou framework relacionado +ao log. Usuários que utilizam logs são chamados de `user`. [RFC 2119]: http://tools.ietf.org/html/rfc2119 -## 1. Specification +## 1. Especificação -### 1.1 Basics +### 1.1 Noções básicas -- The `LoggerInterface` exposes eight methods to write logs to the eight - [RFC 5424][] levels (debug, info, notice, warning, error, critical, alert, - emergency). +- O `LoggerInterface` expõe oito método para gravar logs nos oito níveis [RFC 5424][] + (depuração, informações, notificação prévia, aviso, erro, crítico, alerta, emergência). -- A ninth method, `log`, accepts a log level as the first argument. Calling this - method with one of the log level constants MUST have the same result as - calling the level-specific method. Calling this method with a level not - defined by this specification MUST throw a `Psr\Log\InvalidArgumentException` - if the implementation does not know about the level. Users SHOULD NOT use a - custom level without knowing for sure the current implementation supports it. +- Um nono método, `log`, aceita um nível de log como primeiro argumento. Chamar esse método + com uma das constantes com uma das constantes de nível de log DEVE ter o mesmo resultado + quando um método de nível específico é chamado. Chamando este método com um nível não + definido por esta especificação, DEVE retornar um `Psr\Log\InvalidArgumentException` + se a implementação não conhecer o nível. Os usuários NÃO DEVEM usar um nível + personalizado sem saber ao certo se a implementação atual o suporta. [RFC 5424]: http://tools.ietf.org/html/rfc5424 -### 1.2 Message +### 1.2 Messagem -- Every method accepts a string as the message, or an object with a - `__toString()` method. Implementors MAY have special handling for the passed - objects. If that is not the case, implementors MUST cast it to a string. +- Todo Método aceita uma string como a mensagem, ou um objeto com o método + `__toString()`. Implementadores PODEM ter tratamento especial para os + objectos passados. Se esse não for o caso, implementadores DEVEM lança-lo + para uma string. -- The message MAY contain placeholders which implementors MAY replace with - values from the context array. +- A mensagem PODE conter placeholders que os implementadores PODEM substituir + por valores do array em contexto. - Placeholder names MUST correspond to keys in the context array. + Os nomes dos placeholders DEVEM corresponder as chaves do array em contexto. - Placeholder names MUST be delimited with a single opening brace `{` and - a single closing brace `}`. There MUST NOT be any whitespace between the - delimiters and the placeholder name. + Os nomes dos placeholders DEVEM ser delimitados por uma única chave para abertura `{` e + uma única chave de fechamento `}`. NÃO DEVE haver nenhum espaço em branco entre os + delimitadores e o nome do placeholder. - Placeholder names SHOULD be composed only of the characters `A-Z`, `a-z`, - `0-9`, underscore `_`, and period `.`. The use of other characters is - reserved for future modifications of the placeholders specification. + Os nomes dos placeholders DEVEM ser compostos apenas por caracteres `A-Z`, `a-z`, + `0-9`, underscore `_`, e ponto `.`. O uso de outros caracteres é reservado para + futuras modificações na especificação dos placeholders. - Implementors MAY use placeholders to implement various escaping strategies - and translate logs for display. Users SHOULD NOT pre-escape placeholder - values since they can not know in which context the data will be displayed. + Os implementores PODEM usar placeholders para implementar várias estratégias de escape + e traduzir logs para serem exibidos. usuários NÃO DEVEM pré-escapar valores de placeholder + pois eles não podem saber em que contexto os dados serão exibidos. - The following is an example implementation of placeholder interpolation - provided for reference purposes only: + O exemplo de implementação de interpolação de placeholder abaixo, é apenas para fins de referência: ~~~php $val) { - // check that the value can be casted to string + // checa se o valor pode ser convertido em string if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) { $replace['{' . $key . '}'] = $val; } } - // interpolate replacement values into the message and return + // interpola os valores de substituição na messagem e retorna return strtr($message, $replace); } - // a message with brace-delimited placeholder names + // Uma mensagem com nomes de placeholders delimitados por chaves $message = "User {username} created"; - // a context array of placeholder names => replacement values + // Um array de contexto com nomes de placeholders => valores de substituição $context = array('username' => 'bolivar'); - // echoes "User bolivar created" + // mostra na tela "Usuário bolivar criado" echo interpolate($message, $context); ~~~ -### 1.3 Context +### 1.3 Contexto -- Every method accepts an array as context data. This is meant to hold any - extraneous information that does not fit well in a string. The array can - contain anything. Implementors MUST ensure they treat context data with - as much lenience as possible. A given value in the context MUST NOT throw - an exception nor raise any php error, warning or notice. +- Todo método aceita um array como dados de contexto. Isso significa manter + qualquer informação irrelevante que não se encaixe bem em uma string. O + array pode conter qualquer coisa. Implementadores DEVEM garantir que os + dados sejam tratados com o máximo de tolerância possível. Um determinado + valor no contexto NÃO DEVE lançar exceção nem gerar erros ou avisos php. -- If an `Exception` object is passed in the context data, it MUST be in the - `'exception'` key. Logging exceptions is a common pattern and this allows - implementors to extract a stack trace from the exception when the log - backend supports it. Implementors MUST still verify that the `'exception'` - key is actually an `Exception` before using it as such, as it MAY contain - anything. +- Se um objeto do tipo `Exception` for passado nos dados de contexto, este + DEVE estar na chave `'exception'`. Exceções de registro são um padrão + comum e isso permite que os implementadores extraiam um rastreamento da + pilha de exceção quando o backend de logs tem suporte à isto. Implmentadores + DEVEM ainda verificar se a chave `'exception'` é realmente uma `Exception` + antes de usá-la como tal, pois PODE conter qualquer coisa. -### 1.4 Helper classes and interfaces +### 1.4 Classes auxiliares e interfaces -- The `Psr\Log\AbstractLogger` class lets you implement the `LoggerInterface` - very easily by extending it and implementing the generic `log` method. - The other eight methods are forwarding the message and context to it. +- A classe `Psr\Log\AbstractLogger` permite que você implemente facilmente o + `LoggerInterface`, estendendo-o e implementando o métido genérico `log`. Os + Outros oito métodos estão encaminhando a mensagem e o contexto para a mesma. -- Similarly, using the `Psr\Log\LoggerTrait` only requires you to - implement the generic `log` method. Note that since traits can not implement - interfaces, in this case you still have to implement `LoggerInterface`. +- Da mesma forma, usar o `Psr\Log\LoggerTrait` requer apenas que você implmente + o método genérico `log`. Como as traits não podem implementar interfaces, + você ainda tem que, neste caso, implementar o `LoggerInterface`. -- The `Psr\Log\NullLogger` is provided together with the interface. It MAY be - used by users of the interface to provide a fall-back "black hole" - implementation if no logger is given to them. However, conditional logging - may be a better approach if context data creation is expensive. +- O `Psr\Log\NullLogger` é fornecido junto com a interface. PODE ser utilizado + por usuários da interface para fornecer uma implementação de "buraco negro" + caso não seja dado nenhum registrador à eles. No entanto, o log condicional + pode ser uma abordagem melhor se a criação de dados de contesto tiver um + custo alto. -- The `Psr\Log\LoggerAwareInterface` only contains a - `setLogger(LoggerInterface $logger)` method and can be used by frameworks to - auto-wire arbitrary instances with a logger. +- O `Psr\Log\LoggerAwareInterface` contém apenas um método + `setLogger(LoggerInterface $logger)` e pode ser utilizado por frameworks + para conectar-se a instâncias arbitrárias com um registrador. -- The `Psr\Log\LoggerAwareTrait` trait can be used to implement the equivalent - interface easily in any class. It gives you access to `$this->logger`. +- O trait `Psr\Log\LoggerAwareTrait` pode ser utilizado para implementar + uma interface equivalente facilmente em qualquer classe. Isso lhe dá + acesso ao `$this->logger`. -- The `Psr\Log\LogLevel` class holds constants for the eight log levels. +- A classe `Psr\Log\LogLevel` mantém constantes para os oito níveis de log. -## 2. Package +## 2. Pacote -The interfaces and classes described as well as relevant exception classes -and a test suite to verify your implementation are provided as part of the -[psr/log](https://packagist.org/packages/psr/log) package. +As interfaces e classes descritas, bem como as classes de exceção relevantes +e um conjunto de testes para verificar as implementações são fornecidas como +parte do pacote [psr/log](https://packagist.org/packages/psr/log). ## 3. `Psr\Log\LoggerInterface` @@ -153,24 +154,25 @@ and a test suite to verify your implementation are provided as part of the namespace Psr\Log; /** - * Describes a logger instance. + * Descreve uma instância do registrador. * - * The message MUST be a string or object implementing __toString(). + * A mensagem DEVE ser uma string ou um objeto implementado __toString(). * - * The message MAY contain placeholders in the form: {foo} where foo - * will be replaced by the context data in key "foo". + * A mensagem PODE conter espaços placeholders no formulário: {foo} onde foo + * será substituído pelos dados do contexto na chave "foo" * - * The context array can contain arbitrary data, the only assumption that - * can be made by implementors is that if an Exception instance is given - * to produce a stack trace, it MUST be in a key named "exception". + * O array de contexto pode conter dados arbitrários, a única suposição que + * pode ser feita pelos implementadores é que, se uma instância de Exceção + * é dada para produzir um rastreamento da pilha, este deve estar em uma + * chave chamada "exceção". * - * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md - * for the full interface specification. + * Para a especificação completa da interface, acesse + * https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md */ interface LoggerInterface { /** - * System is unusable. + * O sistema está inutilizável. * * @param string $message * @param array $context @@ -179,10 +181,10 @@ interface LoggerInterface public function emergency($message, array $context = array()); /** - * Action must be taken immediately. + * Uma ação deve ser tomada imediatamente. * - * Example: Entire website down, database unavailable, etc. This should - * trigger the SMS alerts and wake you up. + * Exemplo: Site fora do ar, banco de dados indisponível, etc. + * Isso deve acionar os alertas de SMS e acordá-lo. * * @param string $message * @param array $context @@ -191,9 +193,9 @@ interface LoggerInterface public function alert($message, array $context = array()); /** - * Critical conditions. + * Condições críticas. * - * Example: Application component unavailable, unexpected exception. + * Exemplo: Componente de aplicativo indisponível, exceção inesperada. * * @param string $message * @param array $context @@ -202,8 +204,8 @@ interface LoggerInterface public function critical($message, array $context = array()); /** - * Runtime errors that do not require immediate action but should typically - * be logged and monitored. + * Erros de tempo de execução que não exigem ação imediata, mas + * geralmente devem ser registrados e monitorados. * * @param string $message * @param array $context @@ -212,10 +214,10 @@ interface LoggerInterface public function error($message, array $context = array()); /** - * Exceptional occurrences that are not errors. + * Ocorrências excepcionais que não são erros. * - * Example: Use of deprecated APIs, poor use of an API, undesirable things - * that are not necessarily wrong. + * Exemplo: Uso de APIs descontinuadas/obsoletas, uso inadequado de uma API, + * coisas indesejáveis que não são necessariamente erradas. * * @param string $message * @param array $context @@ -224,7 +226,7 @@ interface LoggerInterface public function warning($message, array $context = array()); /** - * Normal but significant events. + * Eventos normais, porém significativos. * * @param string $message * @param array $context @@ -233,9 +235,9 @@ interface LoggerInterface public function notice($message, array $context = array()); /** - * Interesting events. + * Eventos interessantes. * - * Example: User logs in, SQL logs. + * Exemplo: Usuário efetua login, logs do SQL. * * @param string $message * @param array $context @@ -244,7 +246,7 @@ interface LoggerInterface public function info($message, array $context = array()); /** - * Detailed debug information. + * Informação detalhada de depuração. * * @param string $message * @param array $context @@ -253,7 +255,7 @@ interface LoggerInterface public function debug($message, array $context = array()); /** - * Logs with an arbitrary level. + * Logs com nível arbitrário. * * @param mixed $level * @param string $message @@ -272,12 +274,12 @@ interface LoggerInterface namespace Psr\Log; /** - * Describes a logger-aware instance. + * Descreve uma instância de reconhecimento de log. */ interface LoggerAwareInterface { /** - * Sets a logger instance on the object. + * Define uma instância de log no objeto. * * @param LoggerInterface $logger * @return void @@ -294,17 +296,17 @@ interface LoggerAwareInterface namespace Psr\Log; /** - * Describes log levels. + * Descreve os níveis de log. */ class LogLevel { - const EMERGENCY = 'emergency'; - const ALERT = 'alert'; - const CRITICAL = 'critical'; - const ERROR = 'error'; - const WARNING = 'warning'; - const NOTICE = 'notice'; - const INFO = 'info'; - const DEBUG = 'debug'; + const EMERGENCY = 'emergência'; + const ALERT = 'alerta'; + const CRITICAL = 'crítico'; + const ERROR = 'erro'; + const WARNING = 'aviso'; + const NOTICE = 'notificação prévia'; + const INFO = 'informações'; + const DEBUG = 'depuração'; } ~~~ From 5811dd626c685305de0be31fddcc11545bf2a312 Mon Sep 17 00:00:00 2001 From: Walter Marcel Barbosa Garcia Date: Thu, 11 Jul 2019 11:51:46 -0300 Subject: [PATCH 11/11] PSR-4 translated --- _docs/psr/PSR-4-autoloader.md | 93 +++++++++++++++++------------------ 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/_docs/psr/PSR-4-autoloader.md b/_docs/psr/PSR-4-autoloader.md index 03df06f..60696a1 100644 --- a/_docs/psr/PSR-4-autoloader.md +++ b/_docs/psr/PSR-4-autoloader.md @@ -6,76 +6,73 @@ order: 5 # Autoloader -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 [RFC 2119](http://tools.ietf.org/html/rfc2119). +As palavras-chave "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" nesse documento devem ser +interpretadas como descrito na [RFC 2119](http://tools.ietf.org/html/rfc2119). -## 1. Overview +## 1. Visão geral -This PSR describes a specification for [autoloading][] classes from file -paths. It is fully interoperable, and can be used in addition to any other -autoloading specification, including [PSR-0][]. This PSR also describes where -to place files that will be autoloaded according to the specification. +Esse PSR descreve a especificação para a classe [autoloading][]. +É totalmente interoperável. Esse PSR também descreve onde colocar +os arquivos que serão carregados automaticamente de acordo com +a espeficação. -## 2. Specification +## 2. Especificação -1. The term "class" refers to classes, interfaces, traits, and other similar - structures. +1. O termo "classe" refere-se a classes, interfaces, traits, and + outras estruturas similares. -2. A fully qualified class name has the following form: +2. Um nome de classe totalmente qualificado posssui o seguinte formulário: \(\)*\ - 1. The fully qualified class name MUST have a top-level namespace name, - also known as a "vendor namespace". + 1. Um nome de classe totalmente qualificado DEVE ter um namespace de nível superior, + também conhecido como "vendor namespace". - 2. The fully qualified class name MAY have one or more sub-namespace - names. + 2. Um nome de classe totalmente qualificado PODE ter um ou mais nomes de sub-namespaces. - 3. The fully qualified class name MUST have a terminating class name. + 3. Um nome de classe totalmente qualificado DEVE ter uma terminação para o nome da classe. - 4. Underscores have no special meaning in any portion of the fully - qualified class name. + 4. Underscores não tem significado algum em qualquer porção do nome de classe + totalmente qualificado. - 5. Alphabetic characters in the fully qualified class name MAY be any - combination of lower case and upper case. + 5. Caracteres alfabéticos em um nome de classe totalmente qualificado PODEM ser + qualquer combinação de letras maísculas e minúsculas. - 6. All class names MUST be referenced in a case-sensitive fashion. + 6. Todos os nomes de classes DEVEM ser referenciados de modo case-sensitive. -3. When loading a file that corresponds to a fully qualified class name ... +3. Ao carregar um arquivo que corresponde a um nome de classe totalmente qualificado ... - 1. A contiguous series of one or more leading namespace and sub-namespace - names, not including the leading namespace separator, in the fully - qualified class name (a "namespace prefix") corresponds to at least one - "base directory". + 1. Uma série contígua de um ou mais nomes principais de namespaces e sub-namespaces, + sem incluir o separador de namespace inicial, em um nome de classe totalmente + qualificado (um "prefixo de namespace"), corresponde a pelo menos um + "diretório base". - 2. The contiguous sub-namespace names after the "namespace prefix" - correspond to a subdirectory within a "base directory", in which the - namespace separators represent directory separators. The subdirectory - name MUST match the case of the sub-namespace names. + 2. Os nomes de sub-namespaces contíguos após o "prefixo de namespace" correspondem + a um subdiretório dentro de um "diretório base", no qual os separadores de + namespace representam separadores de diretório. O nome do subdiretório DEVE + corresponder ao caso dos nome do sub-namespace. - 3. The terminating class name corresponds to a file name ending in `.php`. - The file name MUST match the case of the terminating class name. + 3. A terminação no nome de uma classe corresponde a um nome de arquivo que termina com `.php`. + O nome do arquivo DEVE corresponder ao caso da terminação no nome de uma classe. -4. Autoloader implementations MUST NOT throw exceptions, MUST NOT raise errors - of any level, and SHOULD NOT return a value. +4. Implementações de Autoloader NÃO DEVEM lançar exceções, NÃO DEVEM mostrar erros + de qualquer nível e NÃO DEVEM retornar um valor. -## 3. Examples +## 3. Exemplos -The table below shows the corresponding file path for a given fully qualified -class name, namespace prefix, and base directory. +A tabela abaixo mostra o caminho correspondente para um determinado nome de classe +totalmente qualificado, prefixo de namespace and diretório base. -| Fully Qualified Class Name | Namespace Prefix | Base Directory | Resulting File Path -| ----------------------------- |--------------------|--------------------------|------------------------------------------- -| \Acme\Log\Writer\File_Writer | Acme\Log\Writer | ./acme-log-writer/lib/ | ./acme-log-writer/lib/File_Writer.php -| \Aura\Web\Response\Status | Aura\Web | /path/to/aura-web/src/ | /path/to/aura-web/src/Response/Status.php -| \Symfony\Core\Request | Symfony\Core | ./vendor/Symfony/Core/ | ./vendor/Symfony/Core/Request.php -| \Zend\Acl | Zend | /usr/includes/Zend/ | /usr/includes/Zend/Acl.php +| Nome de Classe Totalmente Qualificado | Prefixo de Namespace | Diretório Base | Resulting File Path | +| --------------------------------------|----------------------|--------------------------|-------------------------------------------| +| \Acme\Log\Writer\File_Writer | Acme\Log\Writer | ./acme-log-writer/lib/ | ./acme-log-writer/lib/File_Writer.php | +| \Aura\Web\Response\Status | Aura\Web | /path/to/aura-web/src/ | /path/to/aura-web/src/Response/Status.php | +| \Symfony\Core\Request | Symfony\Core | ./vendor/Symfony/Core/ | ./vendor/Symfony/Core/Request.php | +| \Zend\Acl | Zend | /usr/includes/Zend/ | /usr/includes/Zend/Acl.php | -For example implementations of autoloaders conforming to the specification, -please see the [examples file][]. Example implementations MUST NOT be regarded -as part of the specification and MAY change at any time. +Para exemplos de implementação de autoloaders conforme a especificação, por favor, acesse [examples file][]. +Exemplos de implementações NÃO DEVEM ser considerados como parte da especificação e PODEM mudar a qualquer momento. [autoloading]: http://php.net/autoload -[PSR-0]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md [examples file]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader-examples.md