jasny / meta
Define metadata for classes, properties and functions
Installs: 19 673
Dependents: 1
Suggesters: 0
Security: 0
Stars: 1
Watchers: 2
Forks: 3
Open Issues: 0
Requires
- php: >=5.6.0
- jasny/typecast: ~2.1.0
Requires (Dev)
- jasny/php-code-quality: ^1.1.0
README
The Jasny Meta library allows you to attach metadata to a class and class properties. The metadata is available at runtime and can be used to trigger particular behaviour.
Installation
The Jasny Meta package is available on packagist. Install it using composer:
composer require jasny/meta
Annotations
Metadata can be specified through annotations. In PHP annotations are written in the docblock and start
with @
. If you're familiar with writing docblocks, you probably recognize them.
Here's an example of obtaining metadata for given class:
use Jasny\Meta\Factory; $factory = new Factory($source, $cache); $meta = $factory->forClass(FooBar::class);
In here:
$source
is an implementation ofJasny\Meta\Source\SourceInterface
- to obtain metadata from class and return it as associative array$cache
is an implementation ofJasny\Meta\Cache\CacheInterface
- to handle caching meta$meta
returned is an instance ofJasny\Meta\MetaClass
.
Lets look closely at all of those.
Meta Sources
Source is an object that actually obtains metadata from class definition. We have three classes of sources defined:
Jasny\Meta\Source\PhpdocSource
- for obtaining metadata, defined in doc-commentsJasny\Meta\Source\ReflectionSource
- for obtaining some generic information, using reflection methodsJasny\Meta\Source\CombinedSource
- a class that uses other sources to get meta and to merge it in a single output array
PhpdocSource
Given a class:
/** * Original FooBar class * * @package FoosAndBars * @author Jimi Hendrix <jimi-guitars@example.com> */ class FooBar { /** * Very first property * @var array * @required */ public $first; /** * And some more property * @var string|Foo * @version 3.4 * @default 'a_place_for_foo' */ public $secondFoo; /** * Protected properties are not included in fetched meta * @var int */ protected $third; /** * Privates also are not included * @var array */ private $fourth; //Methods and constants are not included in meta for now }
We obtain metadata:
use Jasny\Meta\Source\PhpdocSource; use Jasny\ReflectionFactory\ReflectionFactory; use Jasny\PhpdocParser\PhpdocParser; use Jasny\PhpdocParser\Set\PhpDocumentor; $reflectionFactory = new ReflectionFactory(); $tags = PhpDocumentor::tags(); $phpdocParser = new PhpdocParser($tags); $source = new PhpdocSource($reflectionFactory, $phpdocParser); $meta = $source->forClass(FooBar::class); var_export($meta);
[ 'package' => 'FoosAndBars', 'author' => [ 'name' => 'Jimi Hendrix', 'email' => 'jimi-guitars@example.com' ], '@properties' => [ 'first' => [ 'var' => 'array', 'required' => true ], 'secondFoo' => [ 'var' => 'string|Foo', 'version' => '3.4', 'default' => 'a_place_for_foo' ] ] ]
In here we used two additional dependencies:
Jasny\ReflectionFactory\ReflectionFactory
- class for creating reflections, is defined in Jasny Reflection factoryJasny\PhpdocParser\PhpdocParser
- class for parsing doc-comments, is defined in Jasny PHPDoc parser
ReflectionSource
This class does not take any information from doc-comments, but fetches data using only reflection methods.
Having a class from previous example as input, we obtain metadata:
use Jasny\Meta\Source\ReflectionSource; use Jasny\ReflectionFactory\ReflectionFactory; $reflectionFactory = new ReflectionFactory(); $source = new ReflectionSource($reflectionFactory); $meta = $source->forClass(FooBar::class); var_export($meta);
[ 'name' => 'Some\\Namespace\\FoosAndBars', 'title' => 'foos and bars', '@properties' => [ 'first' => [ 'name' => 'first', 'title' => 'first', 'default' => null ], 'secondFoo' => [ 'name' => 'secondFoo', 'title' => 'second foo', 'default' => 'a_place_for_foo' ] ] ]
$reflectionFactory
dependency is the same as defined in the upper example for PhpdocSource
.
CombinedSource
Here's an example for the same class definition:
$sources = [$phpdocSource, $reflectionSource]; $source = new CombinedSource($sources); $meta = $source->forClass(FooBar::class); var_export($meta);
[ 'package' => 'FoosAndBars', 'author' => [ 'name' => 'Jimi Hendrix', 'email' => 'jimi-guitars@example.com' ], 'name' => 'Some\\Namespace\\FoosAndBars', 'title' => 'foos and bars', '@properties' => [ 'first' => [ 'var' => 'array', 'required' => true, 'name' => 'first', 'title' => 'first', 'default' => null ], 'secondFoo' => [ 'var' => 'string|Foo', 'version' => '3.4', 'name' => 'secondFoo', 'title' => 'second foo', 'default' => 'a_place_for_foo' ] ] ]
As you see, meta, obtained by means of $phpdocSource
and $reflectionSource
, was merged into a single array.
Caching
The second parameter to pass to factory constructor is an instance of Jasny\Meta\Cache\CacheInterface
. It is used to cache metadata between calls for the same class name.
We have two implementations of cache:
Jasny\Meta\Cache\None
- actually does not perform any caching, used to simplify a code for cache usageJasny\Meta\Cache\Simple
- caching into a process memory (so in array). This cache does not persist among different php processes and lasts till the current process ends.
So if you don't want to cache meta, just use a $cache = new Jasny\Meta\Cache\None()
.
Meta
Meta returned by factory is an instance of Jasny\Meta\MetaClass
. It has the following methods to obtain data:
get(string $key, $default = null)
- get class meta by keyis(string $key): bool
- check if meta key exists and is not emptyhas(string $key): bool
- check if meta key exists (can be empty)getProperty(string $name): ?MetaProperty
- obtain metadata for given class property. Result is either null, if property does not exists, or an instance ofJasny\Meta\MetaProperty
getProperties(): array
- get metadata for all class properties as array ofJasny\Meta\MetaProperty
objects
MetaProperty
class implements the first three methods of those (so get
, is
and has
).