PHP resolves an unqualified attribute name using the current namespace and imported symbols. A missing use statement can therefore resolve #[Encrypted] to the wrong class name while the file still parses. Exercise important attributes through reflection in an automated test.
Last updated: October 20, 2026.
<?php
namespace AppAttribute {
use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
final class Encrypted {}
}
namespace AppEntity {
use AppAttributeEncrypted;
final class Patient {
#[Encrypted]
public ?string $phone = null;
}
}
namespace {
$property = new ReflectionProperty(AppEntityPatient::class, 'phone');
foreach ($property->getAttributes() as $attribute) {
if (!class_exists($attribute->getName())) {
throw new LogicException('Unknown attribute: ' . $attribute->getName());
}
$attribute->newInstance();
}
}The explicit import makes the intended class visible in the entity namespace. The reflection check verifies both the resolved class name and whether the attribute can actually be instantiated.
Understand deferred attribute validation
The PHP manual explains that Reflection returns attribute metadata before creating an attribute object. Constructor arguments, target restrictions, and the represented class are validated when ReflectionAttribute::newInstance() is called, not merely when the annotated file is parsed.
A framework may ask only for attributes matching a specific fully qualified class. If the source resolved the short name to another namespace, that lookup returns nothing and the expected behavior may never run. This is especially risky for attributes controlling authorization, validation, serialization, or encryption.
Make attribute mistakes fail during testing
Use explicit imports for application and vendor attributes, enable IDE or static-analysis checks for unknown classes, and add a focused reflection test for behavior-critical metadata. The manual’s attribute-class guidance shows declaring and importing a dedicated class with #[Attribute].
Testing every reflected declaration may be unnecessary. Start with entity properties, controller methods, message handlers, and other locations where missing metadata changes security or stored data. Assert the expected fully qualified attribute name and call newInstance() so invalid arguments or targets also fail.
Continue with PHP namespace structure, Symfony namespace-based services, and debugging PHP with Xdebug.