跳到内容

PropertyInfo 组件

编辑此页

PropertyInfo 组件允许您通过使用不同的元数据来源来获取关于类属性的信息。

虽然 PropertyAccess 组件 允许您读取和写入对象和数组的值,但 PropertyInfo 组件仅使用类定义来提供关于该类中属性的数据类型和可见性(包括通过 getter 或 setter 方法)的信息。

安装

1
$ composer require symfony/property-info

注意

如果您在 Symfony 应用程序之外安装此组件,您必须在代码中 require vendor/autoload.php 文件,以启用 Composer 提供的类自动加载机制。阅读 这篇文章 以获取更多详细信息。

某些 此组件提供的提取器 可能需要额外的依赖项。

用法

要使用此组件,请创建一个新的 PropertyInfoExtractor 实例,并为其提供一组信息提取器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use Example\Namespace\YourAwesomeCoolClass;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;

// a full list of extractors is shown further below
$phpDocExtractor = new PhpDocExtractor();
$reflectionExtractor = new ReflectionExtractor();

// list of PropertyListExtractorInterface (any iterable)
$listExtractors = [$reflectionExtractor];

// list of PropertyTypeExtractorInterface (any iterable)
$typeExtractors = [$phpDocExtractor, $reflectionExtractor];

// list of PropertyDescriptionExtractorInterface (any iterable)
$descriptionExtractors = [$phpDocExtractor];

// list of PropertyAccessExtractorInterface (any iterable)
$accessExtractors = [$reflectionExtractor];

// list of PropertyInitializableExtractorInterface (any iterable)
$propertyInitializableExtractors = [$reflectionExtractor];

$propertyInfo = new PropertyInfoExtractor(
    $listExtractors,
    $typeExtractors,
    $descriptionExtractors,
    $accessExtractors,
    $propertyInitializableExtractors
);

// see below for more examples
$class = YourAwesomeCoolClass::class;
$properties = $propertyInfo->getProperties($class);

提取器排序

数组中提取器实例的顺序很重要:将返回第一个非空结果。 这就是为什么您必须将每个类别的提取器作为单独的数组提供,即使提取器为多个类别提供信息也是如此。

例如,虽然 ReflectionExtractorDoctrineExtractor 都提供列表和类型信息,但最好是

  • ReflectionExtractor 在列表信息方面具有优先级,以便返回类中的所有属性(不仅仅是映射的属性)。
  • DoctrineExtractor 在类型信息方面具有优先级,以便使用实体元数据而不是类型提示来提供更准确的类型信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;
    use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
    use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
    
    $reflectionExtractor = new ReflectionExtractor();
    $doctrineExtractor = new DoctrineExtractor(/* ... */);
    
    $propertyInfo = new PropertyInfoExtractor(
        // List extractors
        [
            $reflectionExtractor,
            $doctrineExtractor
        ],
        // Type extractors
        [
            $doctrineExtractor,
            $reflectionExtractor
        ]
    );

可提取的信息

PropertyInfoExtractor 类公开了公共方法来提取几种类型的信息

注意

请务必将名称(而不是对象)传递给提取器方法

1
2
3
4
5
6
7
// bad! It may work, but not with all extractors
$propertyInfo->getProperties($awesomeObject);

// Good!
$propertyInfo->getProperties(get_class($awesomeObject));
$propertyInfo->getProperties('Example\Namespace\YourAwesomeClass');
$propertyInfo->getProperties(YourAwesomeClass::class);

列表信息

实现 PropertyListExtractorInterface 的提取器提供类上可用的属性列表,作为一个数组,其中包含每个属性名称作为字符串

1
2
3
4
5
6
7
8
9
10
$properties = $propertyInfo->getProperties($class);
/*
    Example Result
    --------------
    array(3) {
        [0] => string(8) "username"
        [1] => string(8) "password"
        [2] => string(6) "active"
    }
*/

类型信息

实现 PropertyTypeExtractorInterface 的提取器为属性提供 广泛的数据类型信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$types = $propertyInfo->getTypes($class, $property);
/*
    Example Result
    --------------
    array(1) {
        [0] =>
            class Symfony\Component\PropertyInfo\Type (6) {
            private $builtinType          => string(6) "string"
            private $nullable             => bool(false)
            private $class                => NULL
            private $collection           => bool(false)
            private $collectionKeyType    => NULL
            private $collectionValueType  => NULL
        }
    }
*/

有关 Type 类的更多信息,请参阅 PropertyInfo 组件

文档块

实现 PropertyDocBlockExtractorInterface 的提取器可以提供属性的完整文档块作为字符串

1
2
3
4
5
6
7
8
$docBlock = $propertyInfo->getDocBlock($class, $property);
/*
    Example Result
    --------------
    string(79):
        This is the subsequent paragraph in the DocComment.
        It can span multiple lines.
*/

7.1

PropertyDocBlockExtractorInterface 接口在 Symfony 7.1 中引入。

描述信息

实现 PropertyDescriptionExtractorInterface 的提取器从属性的注解中提供长描述和短描述,作为字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$title = $propertyInfo->getShortDescription($class, $property);
/*
    Example Result
    --------------
    string(41) "This is the first line of the DocComment."
*/

$paragraph = $propertyInfo->getLongDescription($class, $property);
/*
    Example Result
    --------------
    string(79):
        This is the subsequent paragraph in the DocComment.
        It can span multiple lines.
*/

访问信息

实现 PropertyAccessExtractorInterface 的提取器提供属性是否可读或可写,作为布尔值

1
2
3
4
5
$propertyInfo->isReadable($class, $property);
// Example Result: bool(true)

$propertyInfo->isWritable($class, $property);
// Example Result: bool(false)

ReflectionExtractor 除了属性是否公开之外,还会查找 getter/isser/setter/hasser 方法,以确定其是否可访问。 这基于 PropertyAccess 的工作方式。 它假设驼峰式命名方法的名称遵循 PSR-1。 例如,如果存在 getMyProperty() 方法,则 myPropertymy_property 属性都是可读的;如果存在 setMyProperty() 方法,则都是可写的。

属性可初始化信息

实现 PropertyInitializableExtractorInterface 的提取器提供属性是否可以通过类的构造函数初始化,作为布尔值

1
2
$propertyInfo->isInitializable($class, $property);
// Example Result: bool(true)

isInitializable() 在给定类的构造函数的参数与给定的属性名称匹配时返回 true

提示

主要的 PropertyInfoExtractor 类实现了所有接口,将属性信息的提取委托给已向其注册的提取器。

这意味着每个提取器上的任何可用方法在主要的 PropertyInfoExtractor 类上也是可用的。

类型对象

与其他提取器相比,类型信息提取器提供的信息比可以表示为简单标量值的信息多得多。 因此,类型提取器为属性支持的每种类型返回一个 Type 对象数组。

例如,如果一个属性同时支持 integerstring(通过 @return int|string 注解),PropertyInfoExtractor::getTypes() 将返回一个包含 两个 Type 类实例的数组。

注意

大多数提取器将仅返回一个 Type 实例。 PhpDocExtractor 是目前唯一在数组中返回多个实例的提取器。

每个对象将提供 6 个属性,可在 6 个方法中使用

Type::getBuiltInType()

Type::getBuiltinType() 方法返回内置 PHP 数据类型,它可以是以下字符串值之一:arrayboolcallablefloatintiterablenullobjectresourcestring

Type 类内部的常量,形式为 Type::BUILTIN_TYPE_*,为了方便而提供。

Type::isNullable()

Type::isNullable() 方法将返回一个布尔值,指示属性参数是否可以设置为 null

Type::getClassName()

如果 内置 PHP 数据类型object,则 Type::getClassName() 方法将返回接受的完全限定类名或接口名。

Type::isCollection()

Type::isCollection() 方法将返回一个布尔值,指示属性参数是否为集合 - 一种能够包含其他值的非标量值。 目前,如果满足以下条件,则返回 true

  • 内置 PHP 数据类型array
  • 属性派生的 mutator 方法具有 addremove 前缀(定义为数组 mutator 前缀列表);
  • phpDocumentor 注解的类型为 “collection”(例如 @var SomeClass<DateTime>, @var SomeClass<integer,string>, @var Doctrine\Common\Collections\Collection<App\Entity\SomeEntity> 等)

Type::getCollectionKeyTypes() & Type::getCollectionValueTypes()

如果属性是集合,则可以为集合的键和值类型返回其他类型对象(如果信息可用),通过 Type::getCollectionKeyTypes()Type::getCollectionValueTypes() 方法。

注意

list 伪类型由 PropertyInfo 组件作为键类型为整数的数组返回。

提取器

属性信息的提取由提取器类执行。 提取类可以通过实现正确的接口来提供一种或多种类型的属性信息。

PropertyInfoExtractor 将按设置顺序迭代相关的提取器类,调用适当的方法并返回第一个非 null 的结果。

虽然您可以创建自己的提取器,但以下提取器已可用于涵盖大多数用例

ReflectionExtractor

使用 PHP 反射,ReflectionExtractor 从 setter 和 accessor 方法提供列表、类型和访问信息。 它还可以给出属性的类型(甚至从构造函数参数中提取),以及它是否可以通过构造函数初始化。 它支持返回和标量类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;

$reflectionExtractor = new ReflectionExtractor();

// List information.
$reflectionExtractor->getProperties($class);

// Type information.
$reflectionExtractor->getTypes($class, $property);

// Access information.
$reflectionExtractor->isReadable($class, $property);
$reflectionExtractor->isWritable($class, $property);

// Initializable information
$reflectionExtractor->isInitializable($class, $property);

注意

当使用 Symfony 框架时,当启用 property_info 功能时,此服务会自动注册

1
2
3
4
# config/packages/framework.yaml
framework:
    property_info:
        enabled: true

PhpDocExtractor

注意

此提取器依赖于 phpdocumentor/reflection-docblock 库。

使用 phpDocumentor Reflection 解析属性和方法注解,PhpDocExtractor 提供类型和描述信息。 如果存在依赖库,则此提取器会在 Symfony 框架中的 property_info 中自动注册

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;

$phpDocExtractor = new PhpDocExtractor();

// Type information.
$phpDocExtractor->getTypes($class, $property);
// Description information.
$phpDocExtractor->getShortDescription($class, $property);
$phpDocExtractor->getLongDescription($class, $property);
$phpDocExtractor->getDocBlock($class, $property);

7.1

getDocBlock() 方法在 Symfony 7.1 中引入。

PhpStanExtractor

注意

此提取器依赖于 phpstan/phpdoc-parserphpdocumentor/reflection-docblock 库。

此提取器借助 PHPStan 解析器获取信息。它从属性和方法的注解中收集信息,例如 @var@param@return

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// src/Domain/Foo.php
class Foo
{
    /**
     * @param string $bar
     */
    public function __construct(
        private string $bar,
    ) {
    }
}

// Extraction.php
use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor;
use App\Domain\Foo;

$phpStanExtractor = new PhpStanExtractor();
$phpStanExtractor->getTypesFromConstructor(Foo::class, 'bar');

SerializerExtractor

注意

此提取器依赖于 symfony/serializer 库。

使用来自 groups 元数据 Serializer 组件SerializerExtractor 提供了列表信息。此提取器不会在 Symfony Framework 中自动注册到 property_info 服务中

1
2
3
4
5
6
7
8
9
use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;

$serializerClassMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
$serializerExtractor = new SerializerExtractor($serializerClassMetadataFactory);

// the `serializer_groups` option must be configured (may be set to null)
$serializerExtractor->getProperties($class, ['serializer_groups' => ['mygroup']]);

如果 serializer_groups 设置为 null,则不会检查 serializer groups 元数据,但您只会获得 Serializer 组件考虑的属性(特别是 #[Ignore] 属性会被考虑在内)。

DoctrineExtractor

注意

此提取器依赖于 symfony/doctrine-bridgedoctrine/orm 库。

使用来自 Doctrine ORM 的实体映射数据,DoctrineExtractor 提供了列表和类型信息。此提取器不会在 Symfony Framework 中自动注册到 property_info 服务中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor;

$config = Setup::createAnnotationMetadataConfiguration([__DIR__], true);
$entityManager = EntityManager::create([
    'driver' => 'pdo_sqlite',
    // ...
], $config);
$doctrineExtractor = new DoctrineExtractor($entityManager);

// List information.
$doctrineExtractor->getProperties($class);
// Type information.
$doctrineExtractor->getTypes($class, $property);

ConstructorExtractor

ConstructorExtractor 尝试通过在构造函数参数上使用 PhpStanExtractorReflectionExtractor 来提取属性信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// src/Domain/Foo.php
class Foo
{
    public function __construct(
        private string $bar,
    ) {
    }
}

// Extraction.php
use App\Domain\Foo;
use Symfony\Component\PropertyInfo\Extractor\ConstructorExtractor;

$constructorExtractor = new ConstructorExtractor([new ReflectionExtractor()]);
$constructorExtractor->getTypes(Foo::class, 'bar')[0]->getBuiltinType(); // returns 'string'

创建您自己的提取器

您可以通过创建一个实现以下一个或多个接口的类来创建您自己的属性信息提取器:PropertyAccessExtractorInterfacePropertyDescriptionExtractorInterfacePropertyListExtractorInterfacePropertyTypeExtractorInterfacePropertyInitializableExtractorInterface

如果您已通过 FrameworkBundle 启用了 PropertyInfo 组件,则可以通过将您的提取器类定义为具有以下一个或多个 标签 的服务,从而自动将您的提取器类注册到 property_info 服务中

  • property_info.list_extractor 如果它提供列表信息。
  • property_info.type_extractor 如果它提供类型信息。
  • property_info.description_extractor 如果它提供描述信息。
  • property_info.access_extractor 如果它提供访问信息。
  • property_info.initializable_extractor 如果它提供可初始化信息(它检查属性是否可以通过构造函数初始化)。
这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本