Visão geral dos atributos

(PHP 8)

Os atributos PHP fornecem metadados estruturados e legíveis por máquina para classes, métodos, funções, parâmetros, propriedades e constantes. Eles podem ser inspecionados no momento da execução por meio da API Reflection, permitindo comportamento dinâmico sem modificar o código. Os atributos fornecem uma maneira declarativa de anotar código com metadados.

Atributos permitem o desacoplamento da implementação de um recurso de seu uso. Enquanto interfaces definem estrutura ao impor métodos, atributos fornecem metadados em vários elementos, incluindo métodos, funções, propriedades e constantes. Diferentemente de interfaces, que impõem implementações de métodos, atributos anotam código sem alterar sua estrutura.

Atributos podem complementar ou substituir métodos de interface opcionais fornecendo metadados em vez de estrutura imposta. Considere uma interface ActionHandler que representa uma operação em um aplicativo. Algumas implementações podem exigir uma etapa de configuração, enquanto outras não. Em vez de forçar todas as classes que implementam ActionHandler a definir um método setUp(), um atributo pode indicar requisitos de configuração. Essa abordagem aumenta a flexibilidade, permitindo que os atributos sejam aplicados várias vezes quando necessário.

Exemplo #1 Implementando métodos opcionais de uma interface com Atributos

<?php
interface ActionHandler
{
    public function execute();
}

#[Attribute]
class SetUp {}

class CopyFile implements ActionHandler
{
    public string $fileName;
    public string $targetDirectory;

    #[SetUp]
    public function fileExists()
    {
        if (!file_exists($this->fileName)) {
            throw new RuntimeException("Arquivo não existe");
        }
    }

    #[SetUp]
    public function targetDirectoryExists()
    {
        if (!file_exists($this->targetDirectory)) {
            mkdir($this->targetDirectory);
        } elseif (!is_dir($this->targetDirectory)) {
            throw new RuntimeException("Diretório de destino $this->targetDirectory não é um diretório");
        }
    }

    public function execute()
    {
        copy($this->fileName, $this->targetDirectory . '/' . basename($this->fileName));
    }
}

function executeAction(ActionHandler $actionHandler)
{
    $reflection = new ReflectionObject($actionHandler);

    foreach ($reflection->getMethods() as $method) {
        $attributes = $method->getAttributes(SetUp::class);

        if (count($attributes) > 0) {
            $methodName = $method->getName();

            $actionHandler->$methodName();
        }
    }

    $actionHandler->execute();
}

$copyAction = new CopyFile();
$copyAction->fileName = "/tmp/foo.jpg";
$copyAction->targetDirectory = "/home/user";

executeAction($copyAction);