*/ final readonly class AttributeCollection implements IteratorAggregate, Countable { /** @var WrappedReflectionAttribute[] */ private array $attributes; public function __construct(WrappedReflectionAttribute ...$attributes) { $this->attributes = $attributes; } /** * @return ArrayIterator */ public function getIterator(): ArrayIterator { return new ArrayIterator(array_values($this->attributes)); } public function count(): int { return count($this->attributes); } public function isEmpty(): bool { return empty($this->attributes); } /** * @return array */ public function toArray(): array { return $this->attributes; } /** * @return array */ public function getInstances(): array { return array_map(fn (WrappedReflectionAttribute $attr) => $attr->newInstance(), $this->attributes); } public function getFirstInstance(): ?object { $instances = $this->getInstances(); return $instances[0] ?? null; } public function getByType(string $attributeClass): self { $filtered = []; foreach ($this->attributes as $attribute) { if ($attribute->getName() === $attributeClass) { $filtered[] = $attribute; } } return new self(...$filtered); } public function hasType(string $attributeClass): bool { return ! $this->getByType($attributeClass)->isEmpty(); } public function getFirstByType(string $attributeClass): ?WrappedReflectionAttribute { foreach ($this->attributes as $attribute) { if ($attribute->getName() === $attributeClass) { return $attribute; } } return null; } public function getFirstInstanceByType(string $attributeClass): ?object { $attribute = $this->getFirstByType($attributeClass); return $attribute?->newInstance(); } /** * @return array */ public function getNames(): array { return array_map(fn (WrappedReflectionAttribute $attr) => $attr->getName(), $this->attributes); } /** * @return array */ public function getUniqueNames(): array { return array_unique($this->getNames()); } }