phpdocumentor/type-resolver

基于PSR-5的类名、类型和结构元素名称解析器

1.8.2 2024-02-23 11:10 UTC

README

License: MIT Coveralls Coverage Scrutinizer Code Coverage Scrutinizer Code Quality Packagist Version Packagist Version

TypeResolver 和 FqsenResolver

PSR-5中对DocBlocks中的类型的规范描述了各种关键字和特殊结构,同时也说明了如何将类名的部分名称静态解析为完全限定类名(FQCN)。

PSR-5还引入了一种描述比类、接口和特性更深层次元素的方法,称为完全限定结构元素名称(FQSEN)。使用它,可以引用方法、属性和类常量,以及函数和全局常量。

此软件包提供了两个解析器,它们能够

  1. 解析任何部分类名时返回一系列值对象,并且
  2. 解析任何部分结构元素名称到完全限定的结构元素名称后返回一个FQSEN对象。

安装

安装此库的最简单方法是使用Composer,以下命令

$ composer require phpdocumentor/type-resolver

示例

准备好深入了解了,不想阅读下面的所有文本?请查阅示例文件夹,查看你想完成哪种类型的操作。

关于类型和元素名称

此组件可以用两种方式之一使用

  1. 解析一个类型或
  2. 解析一个完全限定结构元素名称

这两者之间的主要区别在于它可以解析的项目数量。

类型解析器可以解析

  • PHP基本类型或伪基本类型,如字符串或void(@var string@return void)。

  • 复合类型,如字符串数组(@var string[])。

  • 复合类型,如字符串或整数(@var string|integer)。

  • 数组表达式(@var (string|TypeResolver)[]

  • 对象或接口,如TypeResolver类(@var TypeResolver@var \phpDocumentor\Reflection\TypeResolver

    请注意,如果您要传递部分类名,则需要额外的步骤,请参阅解析部分类和FQSEN章节以获取更多信息。

FqsenResolver可以解析的内容

  • 常量表达式(即@see \MyNamespace\MY_CONSTANT
  • 函数表达式(即@see \MyNamespace\myFunction()
  • 类表达式(即@see \MyNamespace\MyClass
  • 接口表达式(即@see \MyNamespace\MyInterface
  • 特性表达式(即@see \MyNamespace\MyTrait
  • 类常量表达式(即@see \MyNamespace\MyClass::MY_CONSTANT
  • 属性表达式(即@see \MyNamespace\MyClass::$myProperty
  • 方法表达式(即@see \MyNamespace\MyClass::myMethod()

解析类型

为了解析类型,您必须实例化类\phpDocumentor\Reflection\TypeResolver并调用它的resolve方法,如下所示

$typeResolver = new \phpDocumentor\Reflection\TypeResolver();
$type = $typeResolver->resolve('string|integer');

在这个例子中,您将收到一个类\phpDocumentor\Reflection\Types\Compound的值对象,它有两个元素,一个是类型为\phpDocumentor\Reflection\Types\String_的元素,另一个是类型为\phpDocumentor\Reflection\Types\Integer的元素。

此解析器的真正力量在于其将部分类名扩展为完全限定类名的功能;但是,为了做到这一点,我们需要一个额外的\phpDocumentor\Reflection\Types\Context类,它将通知解析器给定表达式发生的命名空间以及哪些命名空间别名(或导入)适用。

解析可空类型

PHP 7.1 引入了可空类型,例如 ?string。类型解析器将解析原始类型而不包含可空标记 ?,就像不包含 ? 一样。之后,该类型将被包装在 \phpDocumentor\Reflection\Types\Nullable 对象中。Nullable 类型有一个方法可以获取实际类型。

解析 FQSEN

完全限定结构元素名(FQSEN)是对代码库中另一个元素的引用,可以使用 \phpDocumentor\Reflection\FqsenResolver 类的 resolve 方法进行解析,如下所示

$fqsenResolver = new \phpDocumentor\Reflection\FqsenResolver();
$fqsen = $fqsenResolver->resolve('\phpDocumentor\Reflection\FqsenResolver::resolve()');

在这个例子中,我们解析了一个完全限定结构元素名(意味着它包含完整的命名空间、类名和元素名),并接收一个类型为 \phpDocumentor\Reflection\Fqsen 的值对象。

这个解析器的真正强大之处在于它能够将部分元素名扩展为完全限定结构元素名;但为了做到这一点,我们需要一个额外的 \phpDocumentor\Reflection\Types\Context 类,它会告知解析器给定表达式发生的命名空间以及哪些命名空间别名(或导入)适用。

解析部分类和结构元素名

这个库最好的特性之一是它知道如何将部分类名解析为完全限定的类名。

例如,你有这个文件

namespace My\Example;

use phpDocumentor\Reflection\Types;

class Classy
{
    /**
     * @var Types\Context
     * @see Classy::otherFunction()
     */
    public function __construct($context) {}
    
    public function otherFunction(){}
}

假设你想要解析(并扩展)@var 标记中的类型和 @see 标记中的元素名。

为了让解析器知道如何扩展部分名称,你必须为它们提供一些 上下文,方法是通过实例化一个新的名为 \phpDocumentor\Reflection\Types\Context 的类,并带有命名空间名称和正在使用的别名。

创建上下文

你可以手动创建一个上下文,如下所示

$context = new \phpDocumentor\Reflection\Types\Context(
    '\My\Example', 
    [ 'Types' => '\phpDocumentor\Reflection\Types']
);

或者使用 \phpDocumentor\Reflection\Types\ContextFactory 来根据 Reflector 对象实例化一个新的上下文,或者通过提供你想要提取的命名空间以及给定类型表达式发生的文件中的源代码。

$contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
$context = $contextFactory->createFromReflector(new ReflectionMethod('\My\Example\Classy', '__construct'));

或者

$contextFactory = new \phpDocumentor\Reflection\Types\ContextFactory();
$context = $contextFactory->createForNamespace('\My\Example', file_get_contents('My/Example/Classy.php'));

使用上下文

在你获得上下文后,只需将其与解析器类的 resolve 方法的第二个参数一起传递,解析器将在解析部分名称时考虑这一点。

要获取上述示例中 @var 标记解析的类名,你可以这样做

$typeResolver = new \phpDocumentor\Reflection\TypeResolver();
$type = $typeResolver->resolve('Types\Context', $context);

当你这样做时,你会收到一个 \phpDocumentor\Reflection\Types\Object_ 类的对象,你可以调用它的 getFqsen 方法来接收一个表示完整 FQSEN 的值对象。所以就是 phpDocumentor\Reflection\Types\Context

为什么 FQSEN 被包装在另一个对象 Object_ 中?

类型解析器的 resolve 方法只返回具有 Type 接口的对象,而 FQSEN 是一种常见类型,它不表示类型。此外:在某些情况下,类型可以表示一个“无类型对象”,这意味着它是一个对象(由 object 关键字表示),但不使用 FQSEN 引用特定元素。

另一个例子是如何解析方法的 FQSEN,如上面示例中的 @see 标记所示。要解析它,你可以这样做

$fqsenResolver = new \phpDocumentor\Reflection\FqsenResolver();
$type = $fqsenResolver->resolve('Classy::otherFunction()', $context);

因为 Classy 是当前命名空间中的一个类,它的 FQSEN 将具有 My\Example 命名空间,通过调用 FQSEN 解析器的 resolve 方法,你将收到一个 Fqsen 对象,它指向 \My\Example\Classy::otherFunction()