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);