Jdi na navigaci předmětu

Atributy

  • od PHP 8.0, zápis #[NazevAtributu] (referenční dokumentace)
  • strukturovaná metadata připojená k deklaraci – třídě, metodě, funkci, vlastnosti, konstantě, parametru nebo výčtovému typu
  • náhrada za dříve používané anotace v dokumentačních komentářích (/** @Something */), které PHP samo nijak neinterpretovalo

    // dříve: anotace v komentáři
    /**
     * @deprecated 2.0 Použijte getTotalPriceVat()
     */
    public function getPrice(): float { ... }
    
    // dnes: atribut -- součást syntaxe (základní kontrola)
    #[\Deprecated(
        message: "Použijte getTotalPriceVat()",
        since: "2.0"
    )]
    public function getPrice(): float { ... }
  • atribut sám o sobě chování kódu nemění; vyhodnocuje ho až ten, kdo si ho přečte (PHP, framework, knihovna)
  • atributů může být u jedné deklarace více (#[A, B] nebo na více řádcích), mohou mít argumenty jako konstruktor
  • využívá se v kombinaci s knihovnami

Vestavěné atributy

  • #[\Attribute] – třída reprezentuje atribut
  • #[\Override] (PHP 8.3) – metoda musí překrývat metodu předka nebo rozhraní, jinak chyba při kompilaci; chrání před překlepem v názvu
  • #[\SensitiveParameter] – hodnota parametru se nezobrazí ve stack trace (hesla, tokeny)
  • #[\Deprecated] (PHP 8.4) – volání funkce/metody vyvolá E_USER_DEPRECATED
  • #[\AllowDynamicProperties] – povolí dynamické vlastnosti třídy, které jsou od PHP 8.2 zastaralé

Příklad

abstract class Customer {
    public function getDiscount(): float { return 0.0; }
}

class RegisteredCustomer extends Customer {
    // Překlep v názvu by skončil chybou už při načtení třídy
    #[\Override]
    public function getDiscount(): float { return 5.0; }

    public function setPassword(
        #[\SensitiveParameter] string $password
    ): void { ... }
}

class Order {
    #[\Deprecated(message: "Použijte getTotalPriceVat()")]
    public function getPrice(): float { ... }
}

Vlastní atributy a reflexe

  • jako atribut je možné použít jakoukoli třídu označenou #[\Attribute]
  • volitelně lze omezit, kam smí být připojen (Attribute::TARGET_METHOD, TARGET_PROPERTY, …​), a zda se smí opakovat (Attribute::IS_REPEATABLE)
  • atributy se čtou pomocí Reflection API – metoda getAttributes() vrací seznam, newInstance() vytvoří instanci atributu
  • typické použití: směrování požadavků, validace, mapování na databázi, registrace testů

Příklad

#[\Attribute(\Attribute::TARGET_METHOD)]
class Route {
    public function __construct(
        public string $path,
        public string $method = 'GET',
    ) {}
}

class ProductController {
    #[Route('/products')]
    public function list(): void { ... }

    #[Route('/products', method: 'POST')]
    public function create(): void { ... }
}

// čtení atributů
$reflection = new \ReflectionClass(ProductController::class);
foreach ($reflection->getMethods() as $method) {
    foreach ($method->getAttributes(Route::class) as $attribute) {
        $route = $attribute->newInstance();
        echo "{$route->method} {$route->path} -> {$method->getName()}\n";
    }
}
// GET /products -> list
// POST /products -> create