Reading metadata

Your starting point is instance of RunOpenCode\Component\Metadata\Contract\MetadataReaderInterface. Reader provides you with methods to:

  • Check if class is marked with specific attribute.

  • Get instance of RunOpenCodeComponentMetadataContractClassMetadataInterface` for further processing (i.e. searching for attributes on class, properties and methods).

  • Find properties and methods that are marked with specific attributes. Properties and methods may be searched separately or together. Each property or method found is represented with instance of RunOpenCode\Component\Metadata\Contract\PropertyMetadataInterface and RunOpenCode\Component\Metadata\Contract\MethodMetadataInterface respectively.

Class attributes and members resolution

When reading metadata from classes, getting attributes from class is simple, only attributes from the current class are considered, no inheritance is consulted.

However, should you need to read class attributes from parent classes, you may use RunOpenCode\Component\Metadata\Contract\ClassMetadataInterface::$parent property to traverse the class hierarchy.

When comes to members (properties and methods), library will resolve members navigating the class hierarchy, meaning that members from parent classes will be considered as well. Rules for resolving members are as follows:

  • Private members: All private members are considered from all classes in the hierarchy. This means that if a parent class has a private property or method, it will be included in the results, even though there is a name collision with a child class member.

  • Public and protected members: Only the members from the most derived class are considered. If a child class overrides a public or protected member from a parent class, only the child class member will be included in the results.

This resolution strategy can be explained with the example given below (do note that example uses properties only for brevity, but the same rules apply to methods as well):

 1 <?php
 2
 3 declare(strict_types=1);
 4
 5 use RunOpenCode\Component\Metadata\Attribute as Meta;
 6
 7 #[Meta\Example('foo')]
 8 class ParentClass
 9 {
10     #[Meta\Property('foo_parent')]
11     private string $privateProperty;
12
13     #[Meta\Property('foo_parent')]
14     protected string $protectedProperty;
15
16     #[Meta\Property('foo_parent')]
17     public string $publicProperty;
18 }
19
20 #[Meta\Example('bar')]
21 class ChildClass extends ParentClass
22 {
23     #[Meta\Property('foo_child')]
24     private string $privateProperty;
25
26     #[Meta\Property('foo_child')]
27     protected string $protectedProperty; // overrides parent
28
29     #[Meta\Property('foo_child')]
30     public string $publicProperty; // overrides parent
31 }

By introspecting ChildClass, the following will be resolved:

  • Class attributes: Meta\Example('bar') only.

  • Properties:

    • Private properties: Both Meta\Property('foo_parent') and Meta\Property('foo_child') will be resolved, as they are private to their respective classes.

    • Protected properties: Only Meta\Property('foo_child') will be resolved, as it overrides the parent class property.

    • Public properties: Only Meta\Property('foo_child') will be resolved, as it overrides the parent class property.

Expected results and exceptions

When using metadata reader methods, do note that methods properties(), methods() and members() will always return arrays, even if no members were found with requested attribute.

However, methods get(), property(), method() and member() may throw:

  • RunOpenCode\Component\Metadata\Exception\NotExistsException if there is no attribute of requested type found on class or member, or no members were found with requested attribute.

  • RunOpenCode\Component\Metadata\Exception\UnexpectedResultException.php if there are multiple attributes of requested type found on class, or, there are multiple members found with requested attribute.

In order to avoid exceptions, you may use methods that return arrays, and handle the results accordingly, or use methods has() to check for existence of attributes or members with requested attributes.