Doctrine注釋提供了為PHP類實現自定義注釋功能的功能(這里使用的是v1.6版本)。
composer require doctrine/annotations
官方鏈接:https://www.doctrine-project.org/projects/doctrine-annotations/en/1.6/index.html#introduction
使用大概步驟:
- 定一個注釋模板文件
- 在類文件中使用注釋(可以看做是給模板賦值)
- 讀取注釋
使用示例: https://www.cnblogs.com/cshaptx4869/p/12178960.html
# Route.php (定義一個注解模板)
<?php namespace Util\Annotation; use Doctrine\Common\Annotations\Annotation\Attributes; //use Doctrine\Common\Annotations\Annotation\Enum; //use Doctrine\Common\Annotations\Annotation\Required; /** * 創建一個注釋類 * * Annotation表示該類是一個注解類
* Target表示注解生效的范圍(ALL,CLASS,METHOD,PROPERTY,ANNOTATION) * * @Annotation * @Target({"METHOD"}) * 也可以在這里變量聲明類型 * @Attributes({ * @Attribute("time", type = "int") * }) */ final class Route { /** * @Required() * @var string */ public $route; /** * @Enum({"POST", "GET", "PUT", "DELETE"}) * @var string */ public $method; /** * @var array */ public $param; public $time; public function say() { echo 'hello'; } }
# run.php (使用、讀取)
<?php require 'vendor/autoload.php'; use Util\Annotation\Route; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\FileCacheReader; use Doctrine\Common\Annotations\AnnotationRegistry; /** * Class UserController * 模擬在User控制其中定義注解路由 * @author 銀醬 */ class UserController { /** * 列表 * @Route(route="/user/index",method="GET") */ public function index() { echo __METHOD__; } /** * 注冊 * @Route(route="/user/register",method="POST",param={"token","access"},time=123) */ public function register() { echo __METHOD__; } /** * 顯示 * @Route(route="/user/info",method="POST") */ public function info() { echo __METHOD__; } /** * 更新 * @Route(route="/user/update",method="POST") */ public function update() { } /** * 刪除 * @Route(route="/user/info",method="DELETE") */ public function delete() { echo __METHOD__; } } //echo '<pre>'; // 注釋使用自己的自動加載機制來確定給定的注釋是否具有可以自動加載的對應PHP類 // 配置注釋自動加載(2.0版本中已剔除) AnnotationRegistry::registerLoader('class_exists'); //回調需返回true //AnnotationRegistry::registerFile(__DIR__ . '/Util/Annotation/Route.php'); //注冊文件 //AnnotationRegistry::registerAutoloadNamespace('Util\Annotation'); //注冊命名空間 //AnnotationRegistry::registerAutoloadNamespaces(['Util\\Annotation' => null]); //注冊多個命名空間 // 系統默認 var、author 標記不會識別 $whitelist = [ "after", "afterClass", "backupGlobals", "backupStaticAttributes", "before", "beforeClass", "codeCoverageIgnore*", "covers", "coversDefaultClass", "coversNothing", "dataProvider", "depends", "doesNotPerformAssertions", "expectedException", "expectedExceptionCode", "expectedExceptionMessage", "expectedExceptionMessageRegExp", "group", "large", "medium", "preserveGlobalState", "requires", "runTestsInSeparateProcesses", "runInSeparateProcess", "small", "test", "testdox", "testWith", "ticket", "uses" ]; foreach ($whitelist as $v) { AnnotationReader::addGlobalIgnoredName($v); } $reflectionClass = new \ReflectionClass(UserController::class); $methods = $reflectionClass->getMethods(); //$reader = new AnnotationReader(); //緩存 reader, 開啟debug 若有修改則會更新,否則需手動刪除然后更新 $reader = new FileCacheReader(new AnnotationReader(), "runtime/annotation", true); foreach ($methods as $method) { // 讀取Route的注解 $routeAnnotation = $reader->getMethodAnnotation($method, Route::class); echo '========================' . PHP_EOL; echo "route: {$routeAnnotation->route}" . PHP_EOL . PHP_EOL; echo "method: {$routeAnnotation->method}" . PHP_EOL; $param = print_r($routeAnnotation->param, true); echo "param: {$param}" . PHP_EOL; $routeAnnotations[] = $routeAnnotation; } //var_dump($routeAnnotations);
# 其余實例1
<?php // 錯誤處理機制 register_shutdown_function('myShutDown'); set_error_handler('myError'); set_exception_handler('myException'); // require自動加載文件 require 'vendor/autoload.php'; // 該類是一個輔助類,幾個屬性$value $type $desc將用於描述其他類的屬性、方法或者對象的。 /** * @Annotation * @Target({"ALL"}) */ class AnnotatedDescription { /** * @var mixed */ public $value; /** * @var string */ public $type; /** * @var string */ public $desc; } /** * @AnnotatedDescription("這是一個用於展示Annotation類的例子。") */ class AnnotationDemo { /** * @AnnotatedDescription(desc="這個屬性必須要為String",type="String") * @var String */ private $property = "I am a private property!"; /** * @AnnotatedDescription(value="啦啦") * @var string */ protected $extra; /** * @AnnotatedDescription(desc="不需要傳入參數", type="getter") */ public function getProperty() { return $this->property; } } echo "<pre>"; // Lets parse the annotations use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\FileCacheReader; // 緩存到文件 //$annotationReader = new FileCacheReader(new AnnotationReader(), './cache/annotation', true); $annotationReader = new AnnotationReader(); // Get class annotation $reflectionClass = new ReflectionClass(AnnotationDemo::class); // public function getClassAnnotations(\ReflectionClass $class); 訪問類的所有注釋 $classAnnotations = $annotationReader->getClassAnnotations($reflectionClass); echo "========= CLASS ANNOTATIONS =========" . PHP_EOL; print_r($classAnnotations); $annotationDemoObject = new AnnotationDemo(); $reflectionObject = new ReflectionObject($annotationDemoObject); $objectAnnotations = $annotationReader->getClassAnnotations($reflectionObject); echo "========= OBJECT ANNOTATIONS =========" . PHP_EOL; print_r($objectAnnotations); $reflectionProperty = new ReflectionProperty(AnnotationDemo::class, 'property'); // public function getPropertyAnnotations(\ReflectionProperty $property); 訪問屬性的所有注釋 $propertyAnnotations = $annotationReader->getPropertyAnnotations($reflectionProperty); echo "========= PROPERTY ANNOTATIONS =========" . PHP_EOL; print_r($propertyAnnotations); $reflectionMethod = new ReflectionMethod(AnnotationDemo::class, 'getProperty'); // public function getMethodAnnotations(\ReflectionMethod $method); 訪問方法的所有注釋 $methodAnnotations = $annotationReader->getMethodAnnotations($reflectionMethod); echo "========= Method ANNOTATIONS =========" . PHP_EOL; print_r($methodAnnotations); function myException($e) { var_dump('<h3 style="color:red;">myException:'.$e->getMessage().'</h3>'); } function myError($code, $msg, $file, $line) { var_dump(compact('code', 'msg', 'file', 'line')); } function myShutDown() { $data = error_get_last(); if(is_null($data)){ var_dump('nothing error'); } else { var_dump('error',$data); } }
# 其余實例2
<?php set_exception_handler('my_exception'); require_once 'vendor/autoload.php'; use Doctrine\Common\Annotations\AnnotationReader; /** * 如果您想定義自己的注釋,只需將它們分組到一個名稱空間中,並在AnnotationRegistry中注冊這個名稱空間 * 注釋類必須包含帶有文本的類級docblock Annotation * @Annotation * * 表明注釋類型適用於的類元素的類型,即注入注釋允許的范圍 * 可選值 CLASS,PROPERTY,METHOD,ALL,ANNOTATION ,可選一個或者多個 * 如果在當前上下文中不允許注釋,則會得到一個AnnotationException * @Target({"METHOD","PROPERTY","CLASS"}) * * 修飾屬性 * @Attributes({ * @Attribute("func", type="string"), * }) */ class A { public $value; /** * @var string */ public $name; /** * 注釋解析器使用phpdoc注釋 var 或 Attributes and Attribute 的組合,檢查給定的參數 * 可選值 mixed,boolean,bool,float,string,integer,array,SomeAnnotationClass,array<integer>,array<SomeAnnotationClass> * 如果數據類型不匹配,則會得到一個AnnotationException * @var integer */ public $age; /** * @var array */ public $sex; public $func; /** * 定義為字段必填,否則報AnnotationException異常 * @Required * * 限制可選值,出錯報AnnotationException異常 * @Enum({"NORTH", "SOUTH", "EAST", "WEST"}) */ public $option; // 如果存在構造函數存在參數,則會把組值傳給這個參數;反之,如果沒有構造函數,則直接將值注入到公共屬性 public function __construct() { } } /** * @A("類注釋") */ class B { /** * 屬性注釋 * @A(name="tom",age=18,sex={"male","fmale","secret"},option="NORTH") */ public $param; /** * 方法注釋 * @A(func="say") */ public function say() { } } $reflection = new ReflectionClass(B::class); $reader = new AnnotationReader(); // 返回的是對象 $AClassAnnotation = $reader->getPropertyAnnotation($reflection->getProperty('param'), A::class); // 返回的是對象組成的數組 //$AClassAnnotation = $reader->getPropertyAnnotations($reflection->getProperty('param')); //$AClassAnnotation = $reader->getMethodAnnotation($reflection->getMethod('say'), A::class); //$AClassAnnotation = $reader->getClassAnnotation($reflection, A::class); dump($AClassAnnotation); function my_exception($exception) { echo '<div class="alert alert-danger">'; echo '<b>Fatal error</b>: Uncaught exception \'' . get_class($exception) . '\' with message '; echo $exception->getMessage() . '<br>'; echo 'Stack trace:<pre>' . $exception->getTraceAsString() . '</pre>'; echo 'thrown in <b>' . $exception->getFile() . '</b> on line <b>' . $exception->getLine() . '</b><br>'; echo '</div>'; exit(); } function dump($data) { echo '<pre>'; var_dump($data); exit(); }
# 其他事項:
// 注釋使用自己的自動加載機制來確定給定的注釋是否具有可以自動加載的對應PHP類
// 配置注釋自動加載3種方式(2.0中已刪除)
AnnotationRegistry::registerLoader('class_exists'); //回調需返回true
//AnnotationRegistry::registerFile(__DIR__ . '/Util/Annotation/Route.php'); //注冊文件
//AnnotationRegistry::registerAutoloadNamespace('Util\Annotation'); //注冊命名空間
//AnnotationRegistry::registerAutoloadNamespaces(['Util\\Annotation' => null]); //注冊多個命名空間
// 添加標簽白名單 系統默認去除author 和 var $whitelist = ["author", "after", "afterClass", "backupGlobals", "backupStaticAttributes", "before", "beforeClass", "codeCoverageIgnore*", "covers", "coversDefaultClass", "coversNothing", "dataProvider", "depends", "doesNotPerformAssertions", "expectedException", "expectedExceptionCode", "expectedExceptionMessage", "expectedExceptionMessageRegExp", "group", "large", "medium", "preserveGlobalState", "requires", "runTestsInSeparateProcesses", "runInSeparateProcess", "small", "test", "testdox", "testWith", "ticket", "uses"]; foreach ($whitelist as $v) { AnnotationReader::addGlobalIgnoredName($v); }
# API:
Access all annotations of a class
public function getClassAnnotations(\ReflectionClass $class);
Access one annotation of a class
public function getClassAnnotation(\ReflectionClass $class, $annotationName);
Access all annotations of a method
public function getMethodAnnotations(\ReflectionMethod $method);
Access one annotation of a method
public function getMethodAnnotation(\ReflectionMethod $method, $annotationName);
Access all annotations of a property
public function getPropertyAnnotations(\ReflectionProperty $property);
Access one annotation of a property
public function getPropertyAnnotation(\ReflectionProperty $property, $annotationName);