Атрибуты предлагают возможность добавлять структурированные машиночитаемые метаданные к объявлениям в коде: классы, методы, функции, параметры, свойства и константы класса могут быть целью атрибута. Затем метаданные, определенные атрибутами, можно проверить во время выполнения с помощью API-интерфейсов Reflection . Таким образом, атрибуты можно рассматривать как язык конфигурации, встроенный непосредственно в код.
С помощью атрибутов можно разделить общую реализацию функции и ее конкретное использование в приложении. В некотором смысле это сопоставимо с интерфейсами и их реализациями. Но там, где интерфейсы и реализации относятся к коду, атрибуты относятся к аннотированию дополнительной информации и конфигурации. Интерфейсы могут быть реализованы классами, но атрибуты также могут быть объявлены в методах, функциях, параметрах, свойствах и константах класса. Таким образом, они более гибкие, чем интерфейсы.
Простым примером использования атрибута является преобразование интерфейса, имеющего необязательные методы, для использования атрибутов. Предположим, 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);
0 комментариев