Введение в атрибуты

(PHP 8)

Атрибуты предлагают возможность добавлять структурированные, машиночитаемые метаданные для следующих деклараций в коде: классы, методы, функции, параметры, свойства и константы класса. Привязанные метаданные можно получить во время исполнения, используя Reflection API. Таким образом, атрибуты можно рассматривать как язык конфигурации, встроенный непосредственно в код.

С помощью атрибутов можно разделить абстрактную реализацию какой-либо функциональности и особенности её использования в коде. В некотором смысле это можно сравнить с разделением интерфейса и его реализаций. Но интерфейсы и реализации - это про код, а атрибуты - про добавление дополнительной информации и конфигурацию. Интерфейсы могут реализовываться только классами, тогда как атрибуты также применимы для методов, функций, параметров, свойств и констант классов. Таким образом, они представляют собой гораздо более гибкий механизм, чем интерфейсы.

Давайте разберём использование атрибутов на простом примере реализации опциональных методов для интерфейса. Допустим, что интерфейс ActionHandler описывает некую операцию в приложении. Одни реализации этого интерфейса требуют предварительной настройки, а другие - нет. И вместо того, чтобы вносить в интерфейс ActionHandler дополнительный метод setUp(), который для части реализаций будет пустым, можно использовать атрибут. Одним из преимуществ этого подхода является то, что мы можем использовать атрибут несколько раз.

Пример #1 Реализация опциональных методов интерфейса с помощью атрибутов

<?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("File does not exist");
        }
    }

    
#[SetUp]
    
public function targetDirectoryExists()
    {
        if (!
file_exists($this->targetDirectory)) {
            
mkdir($this->targetDirectory);
        } elseif (!
is_dir($this->targetDirectory)) {
            throw new 
RuntimeException("Target directory $this->targetDirectory is not a directory");
        }
    }

    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);
add a note add a note

User Contributed Notes

There are no user contributed notes for this page.
To Top