phpvalidationsyntaxannotationsphp-attributes

PHP 8 Attributes: Is it possible to validate metadata passed to attributes or force attribute instantiation?


Playing a little bit with the new PHP 8 attributes (annotations) (https://stitcher.io/blog/attributes-in-php-8) I started to create my own ones.

Simple example:

namespace CisTools\Attribute;

use Attribute;
use CisTools\Exception\BadAttributeMetadataException;

/**
 * For defining a description.
 */
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::TARGET_FUNCTION)]
class Description
{
    /**
     * @param string $description
     * @throws BadAttributeMetadataException
     */
    public function __construct(string $description)
    {
        if (strlen($description) < 10) {
            throw new BadAttributeMetadataException("This is description is too short.");
        }
    }
}

Hoping that the following code would throw an BadAttributeMetadataException unfortunately it finishes successfully:

use CisTools\Attribute\Description;

#[Description("quack")]
class Test {

    public function __construct() {
        echo "hello world";
    }

}

new Test();

Is there away to validate the metadata passed for (custom) attributes? Most probably the attributes have to be instantiated automatically somehow.


Solution

  • Everything is possible - as of today I have implemented a working solution for this problem which can very well be used in libraries (just in case somebody needs that too):

    function cis_shutdown_validate_attributes()
    {
        if(!defined('CIS_DISABLE_ATTRIBUTE_VALIDATION')) {
            foreach(get_declared_classes() as $class) {
                try {
                    $reflection = new ReflectionClass($class);
                } catch (\Throwable $throwable) {
                    continue;
                }
                $attributes = $reflection->getAttributes();
        
                foreach ($attributes as $attribute) {
                    $attribute->newInstance();
                }
            }
        }
    }
    
    register_shutdown_function('cis_shutdown_validate_attributes');
    

    (You may also autoload it: Composer/PSR - How to autoload functions?)