xp-framework/reflection

v3.2.0 2024-08-27 18:19 UTC

README

Build status on GitHub XP Framework Module BSD Licence Requires PHP 7.4+ Supports PHP 8.0+ Latest Stable Version

此库提供了XP框架反射API的替代品。

特性

简洁:此库旨在通过其访问器方法简单地返回NULL来减少类似if (hasX(...)) { getX() }的代码噪声。随着PHP 7中引入null合并运算符??和PHP 8中引入的null安全调用运算符?->(以及在XP编译器中),null处理得到了改进。

PHP 7 & 8:此库在PHP 7(使用编译器的AST库)和PHP 8(使用其本机反射API)中处理PHP 8属性。

子命令:此库提供RFC #0303集成,并为新的XP运行器提供“reflect”子命令。有关如何使用它,请参阅xp help reflect

API

入口点是lang.Reflection类。可以通过传递对象、类型字面量(例如Date::class)、完全限定的类名(例如util.Date)、lang.XPClass或PHP的ReflectionClass实例来构造它。

use lang\Reflection;
use org\example\{Base, Inject, Fixture};

$type= Reflection::type(Fixture::class);

$type->name();                // org.example.Fixture
$type->declaredName();        // Fixture
$type->literal();             // Fixture::class
$type->modifiers();           // Modifiers<public>
$type->comment();             // (api doc comment)
$type->class();               // lang.XPClass instance
$type->classLoader();         // lang.ClassLoader instance
$type->package();             // Package or NULL
$type->parent();              // Type or NULL
$type->interfaces();          // Type[]
$type->traits();              // Type[]
$type->kind();                // Kind::$INTERFACE, Kind::$TRAIT, Kind::$CLASS, Kind::$ENUM
$type->is(Base::class);       // true

if ($type->instantiable()) {
  $instance= $type->newInstance('Testing');
}

$type->isInstance($instance); // true

可以通过迭代annotations()或使用简写方法annotation()来访问注解。

foreach ($type->annotations() as $annotation) {
  $annotation->type();            // Author::class
  $annotation->name();            // 'author'
  $annotation->arguments();       // ['Test', test => true]
  $annotation->argument(0);       // 'Test'
  $annotation->argument('test');  // true
  $annotation->newInstance();     // Author class instance
}

$type->annotation(Inject::class); // Annotation or NULL

可以通过constructor()访问构造函数。与成员一样,它提供了对修饰符、注解及其声明类型的访问器。

$type->constructor();                      // Constructor or NULL

if ($constructor= $type->constructor()) {
  $constructor->name();                    // '__construct'
  $constructor->compoundName();            // 'org.example.Fixture::__construct()'
  $constructor->modifiers();               // Modifiers<public>
  $constructor->comment();                 // (api doc comment)
  $constructor->annotations();             // Annotations
  $constructor->annotation(Inject::class); // Annotation or NULL
  $constructor->declaredIn();              // Type
  $constructor->parameters();              // Parameters
  $constructor->parameter(0);              // Parameter or NULL
  $constructor->newInstance([]);           // (instance of the type)
}

可以使用initializer()控制类型实例化。它接受闭包或实例方法的命名引用。

// Instantiates type without invoking a constructor
// Any passed arguments are discarded silently
$instance= $type->initializer(null)->newInstance();

// Instantiates type by providing a constructor, regardless of whether one exists or not
// Arguments are passed on to the initializer function, which has access to $this
$instance= $type->initializer(function($name) { $this->name= $name; })->newInstance(['Test']);

// Instantiates type by selecting an instance method as an initializer
// The unserialize callback is invoked with ['name' => 'Test']
if ($unserialize= $type->initializer('__unserialize')) {
  $instance= $unserialize->newInstance([['name' => 'Test']]);
}

可以通过迭代或通过按名称的简写查找来访问所有成员(常量、属性和方法)。成员提供了对修饰符、注解及其声明类型的访问器。

$type->constant('POWER');                  // Constant or NULL
$type->property('value');                  // Property or NULL
$type->method('fixture');                  // Method or NULL

foreach ($type->constants() as $name => $constant) {
  $constant->name();                       // 'POWER'
  $constant->compoundName();               // 'org.example.Fixture::POWER'
  $constant->value();                      // 6100
  $constant->modifiers();                  // Modifiers<public>
  $constant->comment();                    // (api doc comment)
  $constant->annotations();                // Annotations
  $constant->annotation(Inject::class);    // Annotation or NULL
  $constant->declaredIn();                 // Type
}

foreach ($type->properties() as $name => $property) {
  $property->name();                       // 'value'
  $property->compoundName();               // 'org.example.Fixture::$value'
  $property->modifiers();                  // Modifiers<public>
  $property->comment();                    // (api doc comment)
  $property->annotations();                // Annotations
  $property->annotation(Inject::class);    // Annotation or NULL
  $property->declaredIn();                 // Type
  $property->constraint();                 // Constraint
  $property->get($instance);               // (property value)
  $property->set($instance, $value);       // (value)
}

foreach ($type->methods() as $name => $method) {
  $method->name();                         // 'fixture'
  $method->compoundName();                 // 'org.example.Fixture::fixture()'
  $method->comment();                      // (api doc comment)
  $method->modifiers();                    // Modifiers<public>
  $method->annotations();                  // Annotations
  $method->annotation(Inject::class);      // Annotation or NULL
  $method->declaredIn();                   // Type
  $method->returns();                      // Constraint
  $method->parameters();                   // Parameters
  $method->parameter(0);                   // Parameter or NULL
  $method->closure($instance);             // Closure instance
  $method->invoke($instance, []);          // (method return value)
}

可以通过迭代parameters()、通过偏移量parameter($position)或通过名称parameter($name)来检索方法和构造函数参数。

$method->parameter(0);                     // Parameter or NULL
$method->parameter('arg');                 // Parameter or NULL

$parameters= $method->parameters();        // Parameters instance
$parameters->at(0);                        // Parameter or NULL
$parameters->named('arg');                 // Parameter or NULL

$args= ['test'];
if ($parameters->accept($args)) {
  $method->invoke(null, $args);
}

foreach ($parameters as $name => $parameter) {
  $parameter->position();                 // 0
  $parameter->name();                     // 'arg'
  $parameter->variadic();                 // false
  $parameter->optional();                 // true
  $parameter->default();                  // (parameter default value)
  $parameter->constraint();               // Constraint
  $parameter->annotations();              // Annotations
  $parameter->annotation(Inject::class)   // Annotation or NULL
}

可以通过将命名空间名称传递给Reflection::of()来对包进行反射。

use lang\Reflection;

$package= Reflection::of('org.example');

$package->name();          // org.example
$package->literal();       // 'org\example'
$package->type('Fixture'); // Type instance
$package->types();         // iterable with Type instances
$package->parent()         // Package or NULL
$package->children();      // iterable with Package instances
$package->classLoaders();  // iterable with lang.ClassLoader instances