PropertyInfo组件

PropertyInfo组件能够让你使用不同资源的metadata(元数据)来得到类中的属性信息。

虽然PropertyAccess组件组件让你能够从对象和数组中进行读写,但PropertyInfo组件只是单纯配合类的定义,来提供关于数据类型和可见性的相关信息——包括通过getter和setter——这两个来自类中属性的方法(来获取)。

安装 

你可以通过下述两种方式安装:

然后,包容vendor/autoload.php文件,以开启Composer提供的自动加载机制。否则,你的程序将无法找到这个Symfony组件的类。

对于本组件提供的某些extractor,可能还需要一些附加的依赖。

用法 

为使用本组件,应先创建一个新的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
36
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Example\Namespace\YourAwesomeCoolClass;
 
// a full list of extractors is shown further below
// 以下是完整的提取器列表
$phpDocExtractor = new PhpDocExtractor();
$reflectionExtractor = new ReflectionExtractor();
 
// array of PropertyListExtractorInterface
// PropertyListExtractorInterface接口的数组
$listExtractors = array($reflectionExtractor);
 
// array of PropertyTypeExtractorInterface
// PropertyTypeExtractorInterface接口的数组
$typeExtractors = array($phpDocExtractor, $reflectionExtractor);
 
// array of PropertyDescriptionExtractorInterface
// PropertyDescriptionExtractorInterface接口的数组
$descriptionExtractors = array($phpDocExtractor);
 
// array of PropertyAccessExtractorInterface
// PropertyAccessExtractorInterface接口的数组
$accessExtractors = array($reflectionExtractor);
 
$propertyInfo = new PropertyInfoExtractor(
    $listExtractors,
    $typeExtractors,
    $descriptionExtractors,
    $accessExtractors
);
 
// see below for more examples
$class = YourAwesomeCoolClass::class;
$properties = $propertyInfo->getProperties($class);

提取器的排序 

数组中的提取器的排序,关乎:第一个non-null的结果将被返回。这就是为什么你一定要提供提取器的每一个分类作为一个独立数组的原因,就算一个提取器对一个以上的分类提供信息。

例如,虽然ReflectionExtractorDoctrineExtractor 都能提供清单和类型的信息,则像下面这样仍然会比较好一点:

  • ReflectionExtractor 对于清单信息有优先级,因此类中的所有属性(不止是映射的属性)都会被返回;

  • DoctrineExtractor对于类型信息有优先级,因此entity的metadata被使用,替代了type-hinting以提供更加精确的type信息。

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 清单提取器
    array(
        $reflectionExtractor,
        $doctrineExtractor
    ),
    // Type extractors 类型提取器
    array(
        $doctrineExtractor,
        $reflectionExtractor
    )
);

可提取的信息 

PropertyInfoExtractor类暴露(exposes)了一些公有方法来提取四种类型的信息:

确保传递一个 名而不是一个对象到extractor的方法中:

1
2
3
4
5
6
7
8
// 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);

List Infomation(清单信息) 

实现了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"
  }
*/

Type Infomation(类型信息) 

实现了PropertyTypeExtractorInterface接口的提取器,提供的是一个属性的可扩展的数据类型信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$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类的信息。

Description Infomation(描述信息) 

实现了PropertyDescriptionExtractorInterface接口的提取器,提供的从属性的annotations中获取的长/短描述之字符串。

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):
    These is the subsequent paragraph in the DocComment.
    It can span multiple lines.
*/

Access Infomation(访问信息) 

实现了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方法,此外还包括属性是否为public公有,以便决定它是否可以访问。这取决于PropertyAccess是如何工作的。

主要的PropertyInfoExtractor类实现了全部四种接口,把属性信息的提取委托给向它注册了的提取器。

这意味着任何一个在单一提取器中可用的方法,都可以在PropertyInfoExtractor主力类上使用。

Type Object(类型对象) 

同其他提取器相比,类型信息提取器提供更多的信息,而不是只有简单的标量值。正因如此,类型提取器对于属性所支持的每一种类型,返回的是一个Type对象数组。

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

多数提取器只返回一个Type实例。PhpDocExtracotr是当前唯一可以“以数组方式”返回多个实例的提取器。

Type::getBuildInType() 

Type::getBuiltInType()方法返回的是一个内建的PHP数据类型,可以是以下9种之一:arrayboolcallablefloatintnullobjectresourcestring

Type类里的常量,出于简便,将以Type::BUILTIN_TYPE_*的方式来提供。

Type::isNullable() 

Type::isNullable()将返回一个布尔值,用于指明属性参数是否可被设为null

Type::getClassName() 

如果built-in PHP data typeobject的话,Type::getClassName()方法将返回可接受的FQCN类名或接口名。

Type::isCollection() 

Type::isCollection()方法将返回布尔值,指明属性参数是否为一个collection(集合)—— 一个“能够容纳其他值”的非标量值。当前,如果满足以下条件,将返回true

  • built-in PHP data typearray,或者

  • 衍生出属性的mutator method(修改器方法)有一个addremove前缀(作为“数组修改器(array mutator)”前缀的列表而被定义)

Type::getCollectionKeyType() 和 Type::getCollectionValueType() 

如果属性是个集合(collection),集合的键和值的类型(如果相关信息可用的话),将作为额外的类型对象被返回,通过Type::getCollectionKeyType()Type::getCollectionValueType()方法来获取。

Extractors(提取器) 

属性信息的提取,是被extractor class(提取器类)来完成的。一个提取器类,通过实现正确的接口,可以提供一或多种属性信息的类型。

PropertyInfoExtractor将遍历相关的提取器类,以它们被设定好的顺序,调用相应的方法,并返回第一个非null结果。

虽然你可以创建自己的提取器,下列可用的提取器覆盖了绝大多数使用场景:

ReflectionExtractor 

使用PHP反射,ReflectionExtractor通过setter和accessor方法,来提供清单、类型和访问信息。对于PHP7和以上版本,它还可提供return和scalar类型。

这个服务在Symfony框架中,自动地注册到property_info服务中:

1
2
3
4
5
6
7
8
9
10
11
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);

PhpDocExtractor 

这个提取器依赖的是phpdocumentor/reflection类库。

使用phpDocumentor Reflection来解析属性和方法的annotations,PhpDocExtractor提供了类型和描述(description)的信息。这个提取器 property_info

1
2
3
4
5
6
7
8
9
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);

SerializerExtractor 

这个提取器依赖的是symfony/serializer类库。

通过使用Serializer component中的groups metadataSerializerExtractor提供了清单信息。在Symfony框架中,这个提取器并没有 自动注册到property_info服务。

1
2
3
4
5
6
7
8
9
10
11
12
use Doctrine\Common\Annotations\AnnotationReader;
use Symfony\Component\PropertyInfo\Extractor\SerializerExtractor;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
 
$serializerClassMetadataFactory = new ClassMetadataFactory(
    new AnnotationLoader(new AnnotationReader)
);
$serializerExtractor = new SerializerExtractor($serializerClassMetadataFactory);
 
// List information. 清单信息
$serializerExtractor->getProperties($class);

DoctrineExtractor 

这个提取器依赖的是symfony/doctrine-bridgedoctrine/orm类库。

通过使用Doctrine Orm中的实体映射数据(entity mapping data),DoctrineExtractor提供了清单和类型信息。在Symfony框架中,这个提取器并没有 自动注册到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->getMetadataFactory());
 
// List information. 清单信息
$doctrineExtractor->getProperties($class);
// Type information. 类型信息
$doctrineExtractor->getTypes($class, $property);

创建你自己的Extractors 

通过创建一个类,令其实现了以下接口中的一个或多个:PropertyAccessExtractorInterfacePropertyDescriptionExtractorInterfacePropertyListExtractorInterfacePropertyTypeExtractorInterface,你也可以创建自己的“属性信息”提取器。

如果你同时开启了PropertyInfo组件和FrameworkBundle,你可以自动注册你的提取器类到property_info服务中,只要把它设成打了以下一个或多个tags(标签)的服务即可:

  • property_info.list_extractor,如果你的提取器提供清单信息。

  • property_info.type_extractor,如果它提供类型信息。

  • property_info.description_extractor,如果它提供description描述信息。

  • property_info.access_extractor,如果它提供“可否访问”信息。

本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。

登录symfonychina 发表评论或留下问题(我们会尽量回复)