> LOADING ARTICLE...
17 Dec 2024 PHP

Atributos PHP 8.3. Como funcionam e a sua Utilização no Mundo Real

Atributos PHP 8.3. Como funcionam e a sua Utilização no Mundo Real Entre as muitas novas funcionalidades os atributos PHP foram uma das mais promissoras que encontrei no PHP 8. Os Atri...

Atributos PHP 8.3. Como funcionam e a sua Utilização no Mundo Real

Atributos PHP 8.3. Como funcionam e a sua Utilização no Mundo Real

atributos php

Entre as muitas novas funcionalidades os atributos PHP foram uma das mais promissoras que encontrei no PHP 8. Os Atributos no PHP 8 foram revistos diversas vezes antes de se estabelecerem na implementação atual, a qual iremos aprofundar um pouco neste artigo.

O que são Atributos PHP?


Essencialmente, Atributos são tipos especiais de classes que podem ser usados para adicionar metadados a outras classes, propriedades, funções, métodos, parâmetros e constantes.

Antes do PHP 8, era prática comum usar “doc-comments” ou “anotações” para adicionar metadados a essas entidades. Por exemplo, aqui está como pode definir um DocBlock de método com metadados que indicam o tipo dos argumentos e o tipo de retorno.

/**
 * Descrição do método aqui.
 *
 * @param Random         $mathRandom
 * @param StdlibDateTime $dateTime
 * @param int            $number
 *
 * @return int
 */
private function doSomething(
    Random $mathRandom, 
    StdlibDateTime $dateTime, 
    int $number
) : int {

}

Estas anotações de comentários são apenas strings e são usados para manter informações estruturadas, e algumas bibliotecas usam as anotações para gerar documentação completa analisando-os, como é o caso do Package L5-Swagger da Darkonline. Além disso, IDEs como o PhpStorm utilizam esses DocBlocks para mostrar diagnósticos de forma inteligente e mostrar avisos e erros em tempo de execução no código, se houver algum.

A maneira de fazer tudo isso nativamente estava ausente, e portanto, os Atributos foram introduzidos no PHP 8.0 para fornecer a capacidade de definir metadados nativamente.

Vamos verificar como você pode definir atributos.

Como Definir Atributos PHP?


Na sua forma mais simples, um atributo PHP pode ser aplicado usando a sintaxe #[attr].

🎯 Curiosidade: A sintaxe de atributos do PHP é inspirada na sintaxe de Atributos do Rust.

Então, se quiser aplicar um atributo a uma classe, por exemplo, pode fazer assim.

#[Attribute]
final class TestClass {

}

Os atributos também podem ser aplicados a várias outras coisas, como propriedades, funções, métodos, parâmetros e constantes, assim.

#[ExampleAttribute]
class Foo
{
    #[ExampleAttribute]
    public const FOO = 'foo';
 
    #[ExampleAttribute]
    public $x;
 
    #[ExampleAttribute]
    public function foo(#[ExampleAttribute] $bar) { }
}
 
$object = new #[ExampleAttribute] class () { };
 
#[ExampleAttribute]
function f1() { }
 
$f2 = #[ExampleAttribute] function () { };
 
$f3 = #[ExampleAttribute] fn () => 1;

Uso Prático
Agora, vamos dar uma olhada em como você pode usar Atributos para recuperar metadados quando aplicados a uma classe. Para isso, você precisará criar um atributo personalizado assim.

Como pode ver, a classe TestAttribute é apenas uma classe regular à qual aplicamos um atributo global usando #[\Attribute]. Para receber metadados, podemos definir um construtor que será usado para recuperar os metadados posteriormente.

#[\Attribute]
class TestAttribute
{
    public function __construct(public string $testArgument)
    {}
}

Uma vez criado, podemos aplicar este atributo personalizado a outra classe assim.

#[TestAttribute('Olá Mundo')]
class MinhaClasse
{

}

Como pode ver, podemos aplicar o atributo personalizado da mesma forma que o atributo global que aplicamos anteriormente. E como pode perceber, também passamos o argumento que servirá como metadado para esta classe.

Agora é hora de recuperar os metadados desta classe. E como faremos? É relativamente simples.

Tudo que você precisa fazer é usar a ReflectionClass incorporada para obter os detalhes sobre MinhaClasse assim.

$reflection = new \ReflectionClass(MinhaClasse::class);
$classAttributes = $reflection->getAttributes();

print_r($classAttributes[0]->newInstance()->testArgument);

Vamos desmembrar isso. Como pode ver, primeiro obtivemos a instância de ReflectionClass passando MinhaClasse como argumento.

Feito isso, podemos obter todos os atributos aplicados a esta classe chamando o método getAttributes.

Isso retornará um array de todos os atributos aplicados à classe. Então, se você imprimir $classAttributes, parecerá assim.

array:1 [▼
  0 => ReflectionAttribute {#1829}
]

Em seguida, para obter o atributo da classe, chamamos o método newInstance() no atributo que retornará a instância do TestAttribute e a partir daí, pode recuperar os metadados chamando o argumento assim.

$classAttributes[0]->newInstance()->testArgument // "Olá Mundo"

Âmbitos de Atributos


Além de aplicar atributos a diferentes entidades em PHP, também é possível definir o âmbito onde um atributo em particular deve ser utilizado.

Para isso, é necessário passar sinalizadores especiais para o Atributo, que incluem o seguinte: Attribute::TARGET_METHOD, Attribute::TARGET_CLASS, Attribute::TARGET_FUNCTION, Attribute::TARGET_PROPERTY, Attribute::TARGET_CLASS_CONSTANT, Attribute::TARGET_PARAMETER e Attribute::TARGET_ALL.

Portanto, se eu quiser limitar um atributo personalizado a ser aplicado apenas a classes PHP, eu faria da seguinte forma.

#[\Attribute(Attribute::TARGET_CLASS)]
class TestAttribute
{
    public function __construct(public string $testArgument)
    {}
}

Agora, se eu tentar aplicar este atributo a um método de classe e obter os metadados por meio de reflexão, como abaixo…

class MyClass
{
    #[TestAttribute('Olá Mundo')]
    public function index()
    {

    }
}

$reflection = new \ReflectionMethod(MyClass::class, 'index');
$methodAttributes = $reflection->getAttributes();

print_r($methodAttributes[0]->newInstance()->testArgument);

… o PHP lançará um erro fatal algo como o abaixo.

Error Attribute “TestAttribute” cannot target method (allowed targets: class)

Como pode ser visto, o erro é autoexplicativo. Ou seja, não é possível aplicar o atributo em métodos de classe, pois ele é projetado para ser usado em classes.

Uso no Mundo Real de Atributos PHP


Enquanto o exemplo anterior parece bom para entender o conceito de Atributos php, a equipa da Spatie encontrou uma maneira interessante de usar Atributos num cenário do mundo real no seu package laravel-route-attributes.

O que essencialmente este pacote faz é fornecer anotações para registrar automaticamente rotas em aplicações Laravel em execução no PHP 8.

Você pode registrar rotas diretamente aplicando um atributo à ação do controlador assim.

use Spatie\RouteAttributes\Attributes\Get;

class MyController
{
    #[Get('minha-rota')]
    public function meuMetodo()
    {

    }
}

Este atributo registrará automaticamente esta rota:

Route::get('minha-rota', [MyController::class, 'meuMetodo']);

Como pode ser visto, o atributo Spatie\RouteAttributes\Attributes\Get aplicado aqui pode ser usado para registrar a rota de obtenção. Existem outros atributos para o restante dos verbos HTTP que você pode usar assim.

#[Spatie\RouteAttributes\Attributes\Post('minha-uri')]
#[Spatie\RouteAttributes\Attributes\Put('minha-uri')]
#[Spatie\RouteAttributes\Attributes\Patch('minha-uri')]
#[Spatie\RouteAttributes\Attributes\Delete('minha-uri')]
#[Spatie\RouteAttributes\Attributes\Options('minha-uri')]

Pode ainda usar o metodo apiResource para gerar automaticamente as rotas em todos os metodos predefinidos pelo laravel tal como o exemplo seguinte:

use Spatie\RouteAttributes\Attributes\Resource;

#[Prefix('api/v1')]
#[Resource(
    resource: 'photos.comments', 
    apiResource: true,
    shallow: true, 
    parameters: ['comments' => 'comment:uuid'],
    names: 'api.v1.photoComments',
    except: ['destroy'],
)]
// OR #[ApiResource(resource: 'photos.comments', shallow: true, ...)]
class PhotoCommentController
{   
    public function index(Photo $photo)
    {
    }

    public function store(Request $request, Photo $photo)
    {
    }

    public function show(Comment $comment)
    {
    }

    public function update(Request $request, Comment $comment)
    {
    }
}

Podemos usar com metodos customizados:

use Spatie\RouteAttributes\Attributes\Get;

class MyController
{
    #[Get('my-route', name: "my-route-name")]
    public function myMethod()
    {
    }
}

Ou ainda adicionar os nossos middlewares:

use Spatie\RouteAttributes\Attributes\Get;

class MyController
{
    #[Get('my-route', middleware: MyMiddleware::class)]
    public function myMethod()
    {

    }
}
webhs
Alojamento recomendado pela DigitalDev

Conclusão:

Os Atributos PHP 8.3 representam uma adição significativa ao arsenal de recursos dos programadores PHP, oferecendo uma maneira mais eficaz e nativa de adicionar metadados a diferentes partes do código. Ao contrário das práticas tradicionais de “doc-comments”, os Atributos proporcionam uma abordagem mais limpa e estruturada para enriquecer o código com informações adicionais.

Baseado em : https://www.amitmerchant.com/how-to-use-php-80-attributes/

About Post Author

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *

> COOKIE_CONSENT_REQUIRED

We use essential cookies for the site to work, and analytics cookies (Google Analytics) to understand how you use it. Analytics cookies are only enabled with your consent. Privacy Policy