A robust, powerful, easy to use attribute parser for PHP

in PHP7 months ago (edited)

Announcing AttributeUtils

After sitting on it for a while, I am pleased to release a PHP library for robust, powerful attribute handling in PHP 8.1: Crell/AttributeUtils. It's a robust, centralized tool for slicing, dicing, and reverse engineering classes in PHP using attributes.

The basics

The basic model of Attribute Utils is to analyze a class "with respect to" some attribute. That attribute may be defined on the class, or not. (Both options have meaning.) That attribute may be associated with attributes on properties or methods, which are all scanned together to produce a picture of a class.

For example, this attribute class implements an interface that tells the library to also scan properties of a class for the MyProperty attribute.

#[\Attribute(\Attribute::TARGET_CLASS)]
class MyClass implements ParseProperties
{
    public readonly array $properties;

    public function propertyAttribute(): string
    {
        return MyProperty::class;
    }

    public function setProperties(array $properties): void
    {
        $this->properties = $properties;
    }

    public function includePropertiesByDefault(): bool
    {
        return true;
    }
}

#[\Attribute(\Attribute::TARGET_PROPERTY)]
class MyProperty
{
    public function __construct(
        public readonly string $column = '',
    ) {}
}

#[MyClass]
class Something
{
    #[MyProperty(column: 'beep')]
    protected property $foo;
    
    private property $bar;
}

$attrib = $analyzer->analyze(Something::class, MyClass::class);

The same works for methods, constants, and methods can also scan their parameters in the same way.

Reflection

The Analzyer class can also opt-in to being passed the reflection object whence it came. That allows and an attribute to set its own defaults based on reflection information on the class, property, method, etc. that it came from.

#[\Attribute]
class AttribWithName implements FromReflectionClass 
{
    public readonly string $name;
    
    public function __construct(?string $name = null) 
    {
        if ($name) {
            $this->name = $name;
        }
    }
    
    public function fromReflection(\ReflectionClass $subject): void
    {
        $this->name ??= $subject->getShortName();
    }
}

Advanced features

There's a lot more that the Attribute Utils Analzyer can do, which is documented in the project README. It can opt-in to default values for missing attributes, excluding values, allowing attributes to be inherited, multi-instance attributes, even transitive-inheritance from referenced classes. All of that is documented in detail on the project page.

Of special note is support for multiple scopes; that is, the ability to have different variants of the same attribute that may be scanned separately from each other. If you've used "serialization groups" before, or want different attributes for different languages, scopes make that easy.

Intended audience

This library is aimed mainly at other library authors. Its goal is to support anyone building libraries that want to leverage attributes in robust ways to enable other functionality, by making working with attributes simple and fast.

If in the past you would have thought to use Doctrine Annotations, think of this as an Attribute-centric alternative on steroids. It takes all the power of PHP attributes and punches them up to 11, in a simple, declarative way.

At the moment, I would consider Attribute Utils in Release Candidate. It's ready to use, and close to feature complete, but I'm looking for feedback before declaring it fully stable. I do not anticipate any BC breaks at this point.

So please, give it a whirl, give feedback, and let your attributes fly in your own projects!

Sort:  

Congratulations @crell! You have completed the following achievement on the Hive blockchain and have been rewarded with new badge(s):

You received more than 250 HP as payout for your posts, comments and curation.
Your next payout target is 500 HP.
The unit is Hive Power equivalent because post and comment rewards can be split into HP and HBD

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

To support your work, I also upvoted your post!

Check out the last post from @hivebuzz:

Hive Power Up Month - Feedback from April day 21
Support the HiveBuzz project. Vote for our proposal!