此PSR的目的是提供定义创建PSR-7对象的方法的工厂接口。
PSR-7的当前规范允许通过创建不可变副本来修改大多数对象。但是,有两个值得注意的例外:
StreamInterface
是一个基于资源的可变对象,该资源仅允许在资源可写时写入资源。UploadedFileInterface
是基于资源的只读对象,该资源不提供修改功能。前者是PSR-7中间件的一个重要痛点,因为它可以使响应处于不完整状态。如果附加到响应主体的流不可搜索或不可写,则无法从已写入主体的错误条件中恢复。
通过提供工厂来创建新流可以避免这种情况。由于缺乏HTTP对象工厂的正式标准,开发人员必须依赖特定的供应商实现才能创建这些对象。
另一个痛点是编写可重用的中间件或请求处理程序。在这种情况下,包作者可能需要创建并返回响应。但是,创建离散实例然后将包绑定到特定的PSR-7实现。如果这些包依赖于请求工厂接口,则它们可以保持与PSR-7实现无关。
为工厂创建正式标准将允许开发人员避免依赖于特定实现,同时能够在必要时创建新对象。
已根据实例化后是否可以修改对象来选择工厂方法定义。对于无法修改的接口,必须在实例化时定义所有对象属性。
在UriInterface
完整URI 的情况下,为方便起见,可以传递URI。
使用的方法名称不会发生冲突。这允许单个类在适当时实现多个接口。
PSR-7的所有当前实现都定义了它们自己的要求。在大多数情况下,所需参数与建议的工厂方法相同或不太严格。
Diactoros是服务器使用的第一个HTTP消息实现之一,并且是与PSR-7规范并行开发的。
Request
没有必需的参数,方法和URI默认null
。Response
没有必需的参数,状态代码默认为200
。ServerRequest
没有必要的参数。包含一个单独的
ServerRequestFactory
用于创建全局变量的请求。Stream
需要string|resource $stream
身体。UploadedFile
要求string|resource $streamOrFile
,int $size
,
int $errorStatus
。错误状态必须是PHP上载常量。Uri
没有必需参数,string $uri
默认为空。总体而言,这种方法与拟议的工厂非常相似。在某些情况下,Diactoros提供了更多选项,这些选项对于有效对象不是必需的。建议的上载文件工厂允许大小和错误状态是可选的。
Guzzle是一种HTTP消息实现,专注于客户端使用。
Request
需要string $method
和string|UriInterface $uri
。Response
没有必需的参数,状态代码默认为200
。Stream
需要resource $stream
身体。Uri
没有必需参数,string $uri
默认为空。面向客户端使用,Guzzle不包含ServerRequest
或
UploadedFile
实现。
总体而言,这种方法也与拟议的工厂非常相似。一个值得注意的区别是Guzzle要求使用资源构造流并且不允许使用字符串。但是,它确实包含一个辅助函数stream_for
,它将从一串内容和一个try_fopen
将从文件路径创建资源的函数创建一个流。
Slim是一个微框架,它使用3.0版本的HTTP消息。
Request
要求string $method
,UriInterface $uri
,
HeadersInterface $headers
,array $cookies
,array $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 $scheme
和string $host
。包含createFromString($uri)
可用于Uri
从字符串创建的工厂方法。Slim仅面向服务器使用,不包含实现Request
。上面列出的实现是一个实现ServerRequest
。
在比较的方法中,Slim与拟议的工厂最不同。最值得注意的是,该Request
实现包含特定于框架的要求,这些要求未在HTTP消息规范中定义。包含的工厂方法通常与建议的工厂类似。
建立此标准最困难的任务是定义接口的方法签名。由于PSR-7中没有关于明确要求哪些值的明确声明,因此必须根据接口是否具有复制和修改对象的方法来推断只读属性。
虽然PSR-7不针对PHP 7,但本规范的作者指出,在撰写本文时(2018年4月),PHP 5.6在15个月前停止接收错误修正,并且将在8个月内不再收到安全补丁。PHP 7.0本身将在7个月内停止接收安全修复程序(有关当前支持的详细信息,请参阅PHP支持的版本文档)。由于规范是长期的,作者认为规范应该针对在可预见的未来支持的版本; PHP 5不会。因此,从安全角度来看,针对PHP 7下的任何内容都是对用户的伤害,因为这样做会默认使用不受支持的PHP版本。
此外,同样重要的是,PHP 7使我们能够为我们定义的接口提供返回类型提示。这保证了最终用户的强大,可预测的合同,因为他们可以假设实现返回的值将完全符合他们的预期。
每个提议的接口(主要)负责产生一种PSR-7类型。这允许消费者对他们所需要的内容进行输入:如果他们需要响应,他们会输入提示ResponseFactoryInterface
; 如果他们需要一个URI,他们会输入提示UriFactoryInterface
。通过这种方式,用户可以精确地了解他们的需求。
这样做还允许应用程序开发人员基于他们正在使用的PSR-7实现提供匿名实现,仅生成他们针对特定上下文所需的实例。这减少了样板; 开发人员不需要为未使用的方法编写存根。
ResponseFactoryInterface::createResponse()
包括一个可选的字符串参数,$reasonPhrase
。在PSR-7规范中,您只能在提供状态代码的同时提供原因短语,因为这两个是相关的数据。本规范的作者选择模仿PSR-7
ResponseInterface::withStatus()
签名,以确保在创建的响应中可能存在两组数据。
ServerRequestFactoryInterface::createServerRequest()
包括一个可选的
$serverParams
数组参数。提供此原因的原因是为了确保可以在填充服务器参数的情况下创建实例。在通过它可访问的数据中ServerRequestInterface
,唯一没有mutator方法的数据是对应于服务器参数的数据。因此,必须在初始创建时提供此数据。因此,它作为工厂方法的参数存在。
主要用例ServerRequestFactoryInterface
是ServerRequestInterface
从已知数据创建新
实例。围绕来自超全球的数据编组的任何解决方案都假定:
这两个假设并不总是正确的。使用Swoole,ReactPHP等异步系统时:
$_GET
,$_POST
,$_COOKIE
,和$_FILES
$_SERVER
与标准SAPI相同的元素(例如mod_php,mod-cgi和mod-fpm)此外,不同的标准SAPI $_SERVER
向请求头提供不同的信息和访问,需要不同的方法来满足请求的初始填充。
因此,为超级全局的实例填充设计接口超出了本规范的范围,并且应该主要是实现特定的。
主要用例RequestFactoryInterface
是创建请求,任何请求的唯一必需值是请求方法和URI。虽然
RequestFactoryInterface::createRequest()
可以接受一个UriInterface
实例,但它也允许一个字符串。
理由是双重的。首先,大多数用例是创建请求实例; 创建URI实例是次要的。需要一种UriInterface
手段用户要么也需要访问a UriFactoryInterface
,否则RequestFactoryInterface
就会对a有严格的要求
UriFactoryInterface
。第一种方法使工厂的消费者使用变得复杂,第二种方法使工厂的开发人员或创建工厂实例的人员的使用变得复杂。
其次,UriFactoryInterface
提供了一种创建
UriInterface
实例的方法,即来自字符串URI。如果URI的创建基于字符串,则没有理由RequestFactoryInterface
不允许相同的语义。此外,在开发此提案时调查的每个PSR-7实现在创建RequestInterface
实例时都允许使用字符串URI
,因为该值随后传递给UriInterface
它们提供的任何
实现。因此,接受字符串是有利的并且遵循现有的语义。
该PSR由FIG工作组制作,成员如下:
工作组还要感谢以下方面的贡献:
注意:顺序按时间顺序递减。