PSR-17元文档

HTTP工厂Meta

1.总结

此PSR的目的是提供定义创建PSR-7对象的方法的工厂接口

为什么要打扰?

PSR-7的当前规范允许通过创建不可变副本来修改大多数对象。但是,有两个值得注意的例外:

  • StreamInterface 是一个基于资源的可变对象,该资源仅允许在资源可写时写入资源。
  • UploadedFileInterface 是基于资源的只读对象,该资源不提供修改功能。

前者是PSR-7中间件的一个重要痛点,因为它可以使响应处于不完整状态。如果附加到响应主体的流不可搜索或不可写,则无法从已写入主体的错误条件中恢复。

通过提供工厂来创建新流可以避免这种情况。由于缺乏HTTP对象工厂的正式标准,开发人员必须依赖特定的供应商实现才能创建这些对象。

另一个痛点是编写可重用的中间件或请求处理程序。在这种情况下,包作者可能需要创建并返回响应。但是,创建离散实例然后将包绑定到特定的PSR-7实现。如果这些包依赖于请求工厂接口,则它们可以保持与PSR-7实现无关。

为工厂创建正式标准将允许开发人员避免依赖于特定实现,同时能够在必要时创建新对象。

3.范围

3.1目标

  • 提供一组接口,用于定义创建PSR-7兼容对象的方法。

3.2非目标

  • 提供PSR-7工厂的具体实施。

4.方法

4.1选择方法

已根据实例化后是否可以修改对象来选择工厂方法定义。对于无法修改的接口,必须在实例化时定义所有对象属性。

UriInterface完整URI 的情况下,为方便起见,可以传递URI。

使用的方法名称不会发生冲突。这允许单个类在适当时实现多个接口。

4.2现有实施

PSR-7的所有当前实现都定义了它们自己的要求。在大多数情况下,所需参数与建议的工厂方法相同或不太严格。

4.2.1 Diactoros

Diactoros是服务器使用的第一个HTTP消息实现之一,并且是与PSR-7规范并行开发的。

  • Request没有必需的参数,方法和URI默认null
  • Response没有必需的参数,状态代码默认为200
  • ServerRequest没有必要的参数。包含一个单独的 ServerRequestFactory用于创建全局变量的请求。
  • Stream需要string|resource $stream身体。
  • UploadedFile要求string|resource $streamOrFileint $sizeint $errorStatus错误状态必须是PHP上载常量。
  • Uri没有必需参数,string $uri默认为空。

总体而言,这种方法与拟议的工厂非常相似。在某些情况下,Diactoros提供了更多选项,这些选项对于有效对象不是必需的。建议的上载文件工厂允许大小和错误状态是可选的。

4.2.2 Guzzle

Guzzle是一种HTTP消息实现,专注于客户端使用。

  • Request需要string $methodstring|UriInterface $uri
  • Response没有必需的参数,状态代码默认为200
  • Stream需要resource $stream身体。
  • Uri没有必需参数,string $uri默认为空。

面向客户端使用,Guzzle不包含ServerRequestUploadedFile实现。

总体而言,这种方法也与拟议的工厂非常相似。一个值得注意的区别是Guzzle要求使用资源构造流并且不允许使用字符串。但是,它确实包含一个辅助函数stream_for ,它将从一串内容和一个try_fopen 将从文件路径创建资源的函数创建一个流

4.2.3修身

Slim是一个微框架,它使用3.0版本的HTTP消息。

  • Request要求string $methodUriInterface $uriHeadersInterface $headersarray $cookiesarray $serverParams,和 StreamInterface $body包含createFromEnvironment(Environment $environment) 特定于框架但与提议类似的工厂方法createServerRequestFromArray
  • Response没有必需的参数,状态代码默认为200
  • Stream需要resource $stream身体。
  • UploadedFile需要string $file源文件。包含parseUploadedFiles(array $uploadedFiles)用于创建UploadedFile实例数组$_FILES或类似格式的工厂方法还包含一个createFromEnvironment(Environment $env)特定于框架并使用的工厂方法parseUploadedFiles
  • Uri需要string $schemestring $host包含createFromString($uri)可用于Uri从字符串创建的工厂方法

Slim仅面向服务器使用,不包含实现Request上面列出的实现是一个实现ServerRequest

在比较的方法中,Slim与拟议的工厂最不同。最值得注意的是,该Request实现包含特定于框架的要求,这些要求未在HTTP消息规范中定义。包含的工厂方法通常与建议的工厂类似。

4.3潜在问题

建立此标准最困难的任务是定义接口的方法签名。由于PSR-7中没有关于明确要求哪些值的明确声明,因此必须根据接口是否具有复制和修改对象的方法来推断只读属性。

5.设计决策

5.1为什么选择PHP 7?

虽然PSR-7不针对PHP 7,但本规范的作者指出,在撰写本文时(2018年4月),PHP 5.6在15个月前停止接收错误修正,并且将在8个月内不再收到安全补丁。PHP 7.0本身将在7个月内停止接收安全修复程序(有关当前支持的详细信息,请参阅PHP支持的版本文档)。由于规范是长期的,作者认为规范应该针对在可预见的未来支持的版本; PHP 5不会。因此,从安全角度来看,针对PHP 7下的任何内容都是对用户的伤害,因为这样做会默认使用不受支持的PHP版本。

此外,同样重要的是,PHP 7使我们能够为我们定义的接口提供返回类型提示。这保证了最终用户的强大,可预测的合同,因为他们可以假设实现返回的值将完全符合他们的预期。

5.2为什么有多个接口?

每个提议的接口(主要)负责产生一种PSR-7类型。这允许消费者对他们所需要的内容进行输入:如果他们需要响应,他们会输入提示ResponseFactoryInterface; 如果他们需要一个URI,他们会输入提示UriFactoryInterface通过这种方式,用户可以精确地了解他们的需求。

这样做还允许应用程序开发人员基于他们正在使用的PSR-7实现提供匿名实现,仅生成他们针对特定上下文所需的实例。这减少了样板; 开发人员不需要为未使用的方法编写存根。

5.3为什么ResponseFactoryInterface的$ reasonPhrase参数存在?

ResponseFactoryInterface::createResponse()包括一个可选的字符串参数,$reasonPhrase在PSR-7规范中,您只能在提供状态代码的同时提供原因短语,因为这两个是相关的数据。本规范的作者选择模仿PSR-7 ResponseInterface::withStatus()签名,以确保在创建的响应中可能存在两组数据。

5.4为什么ServerRequestFactoryInterface的$ serverParams参数存在?

ServerRequestFactoryInterface::createServerRequest()包括一个可选的 $serverParams数组参数。提供此原因的原因是为了确保可以在填充服务器参数的情况下创建实例。在通过它可访问的数据中ServerRequestInterface,唯一没有mutator方法的数据是对应于服务器参数的数据。因此,必须在初始创建时提供此数据。因此,它作为工厂方法的参数存在。

5.5为什么没有工厂可以从superglobals创建ServerRequestInterface?

主要用例ServerRequestFactoryInterfaceServerRequestInterface从已知数据创建新 实例。围绕来自超全球的数据编组的任何解决方案都假定:

  • 超级全球存在
  • 超全球遵循特定的结构

这两个假设并不总是正确的。使用SwooleReactPHP等异步系统时

  • 将不填充标准超全局变量,如$_GET$_POST$_COOKIE,和$_FILES
  • 不会填充$_SERVER与标准SAPI相同的元素(例如mod_php,mod-cgi和mod-fpm)

此外,不同的标准SAPI $_SERVER 向请求头提供不同的信息和访问,需要不同的方法来满足请求的初始填充。

因此,为超级全局的实例填充设计接口超出了本规范的范围,并且应该主要是实现特定的。

5.6为什么RequestFactoryInterface :: createRequest允许字符串URI?

主要用例RequestFactoryInterface是创建请求,任何请求的唯一必需值是请求方法和URI。虽然 RequestFactoryInterface::createRequest()可以接受一个UriInterface实例,但它也允许一个字符串。

理由是双重的。首先,大多数用例是创建请求实例; 创建URI实例是次要的。需要一种UriInterface 手段用户要么也需要访问a UriFactoryInterface,否则RequestFactoryInterface就会对a有严格的要求 UriFactoryInterface第一种方法使工厂的消费者使用变得复杂,第二种方法使工厂的开发人员或创建工厂实例的人员的使用变得复杂。

其次,UriFactoryInterface提供了一种创建 UriInterface实例的方法,即来自字符串URI。如果URI的创建基于字符串,则没有理由RequestFactoryInterface不允许相同的语义。此外,在开发此提案时调查的每个PSR-7实现在创建RequestInterface实例时都允许使用字符串URI ,因为该值随后传递给UriInterface它们提供的任何 实现。因此,接受字符串是有利的并且遵循现有的语义。

6.人

该PSR由FIG工作组制作,成员如下:

工作组还要感谢以下方面的贡献:

7.投票

注意:顺序按时间顺序递减。