(PHP 8)
注解功能提供了代碼中的聲明部分都可以添加結(jié)構(gòu)化、機器可讀的元數(shù)據(jù)的能力, 注解的目標(biāo)可以是類、方法、函數(shù)、參數(shù)、屬性、類常量。 通過 反射 API 可在運行時獲取注解所定義的元數(shù)據(jù)。 因此注解可以成為直接嵌入代碼的配置式語言。
通過注解的使用,在應(yīng)用中實現(xiàn)功能、使用功能可以相互解耦。 某種程度上講,它可以和接口(interface)與其實現(xiàn)(implementation)相比較。 但接口與實現(xiàn)是代碼相關(guān)的,注解則與聲明額外信息和配置相關(guān)。 接口可以通過類來實現(xiàn),而注解也可以聲明到方法、函數(shù)、參數(shù)、屬性、類常量中。 因此它們比接口更靈活。
注解使用的一個簡單例子:將接口(interface)的可選方法改用注解實現(xiàn)。
我們假設(shè)接口 ActionHandler
代表了應(yīng)用的一個操作:
部分 action handler 的實現(xiàn)需要 setup,部分不需要。
我們可以使用注解,而不用要求所有類必須實現(xiàn) ActionHandler
接口并實現(xiàn) setUp()
方法。
因此帶來一個好處——可以多次使用注解。
示例 #1 用注解實現(xiàn)接口的可選方法
<?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);