Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Attributes

An attribute adds typed data to a declaration or parameter. Whim checks the attribute class, its target, its arguments, and whether it may repeat.

Defining an attribute

Mark a class with Whim\Attribute\Attribute:

use Whim\Attribute\Attribute;

#[Attribute(Attribute::TARGET_CLASS)]
final readonly class Table {
  public function __construct(public string $name) {}
}

#[Table('users')]
final class User {}

Applying #[Table('users')] creates a Table value. The arguments follow the same count and type rules as a normal constructor call. Attribute arguments may not read local variables.

An attribute class may have no constructor. Apply it without parentheses:

use Whim\Attribute\Attribute;

#[Attribute(Attribute::TARGET_FUNCTION)]
final class Endpoint {}

#[Endpoint]
function home(): string {
  return '/';
}

Targets

Pass one or more target flags to #[Attribute]:

FlagTarget
TARGET_CLASSclass, interface, or enum
TARGET_FUNCTIONnamed function or closure
TARGET_METHODmethod
TARGET_PROPERTYproperty
TARGET_CLASS_CONSTANTclass-like constant or enum case
TARGET_PARAMETERfunction, method, or closure parameter
TARGET_TYPE_ALIAStype alias
TARGET_NEWTYPEnewtype
TARGET_CONSTANTnamespace constant
TARGET_SYMBOLany named symbol
TARGET_ALLevery supported target

Join flags with |:

use Whim\Attribute\Attribute;

#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
final class Timed {}

With no flag, an attribute accepts every target.

Repeated attributes

An attribute may appear once on one target unless its flags include IS_REPEATABLE.

use Whim\Attribute\Attribute;

#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final readonly class Tag {
  public function __construct(public string $name) {}
}

#[Tag('http')]
#[Tag('public')]
final class Handler {}

Each use stores its own arguments. Source order stays intact.

Reading attributes

Use Whim\Reflection to inspect attributes:

use Whim\Attribute\Attribute;
use Whim\Reflection;

#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
final readonly class Tag {
  public function __construct(public string $name) {}
}

#[Tag('http')]
#[Tag('public')]
final class Handler {}

$handler = Reflection\reflect_class('Handler');
assert!($handler != null);

foreach ($handler->getAttributes::<Tag>() as $attribute) {
  $tag = $attribute->newInstance();
  write_line!($tag->name);
}

Every declaration reflection provides getAttributes::<T>() and getAttributesByName(). Both return attribute reflections without running an attribute constructor. AttributeReflection::newInstance() constructs a fresh attribute value.

Use reflect_function() for a function. A class-like reflection provides its methods, properties, and constants. A method reflection provides its parameters. reflect_object($case)->getEnumCase() finds an enum case. Missing declarations and members return null.

See Reflection for the complete API.

Attributes are values, not comments. The compiler rejects a bad target, a bad argument, a missing attribute class, or an illegal repeat before the program runs.