Annotation

Easyswoole提供了一个轻量级的注解解析工具。

安装

  1. composer require easyswoole/annotation

实现原理

  • 约定
    • 每个注解行为@字符开头,格式为 @METHOD(ARGS)
  • 执行流程如下:
    • 利用php反射得到注释信息
    • 用explode用PHP_EOL分割每行
    • 解析每行的数据,若存在对应的METHOD AnnotationTagInterface ,则把解析得到的ARGS传递给 AnnotationTagInterface 中的 assetValue 方法, 用户可以在该方法中对解析得到的值进行自定义解析。
    • 若为严格模式,如果解析不到正确的数值,则报错。

例子

  1. <?php
  2. use EasySwoole\Annotation\Annotation;
  3. use EasySwoole\Annotation\AbstractAnnotationTag;
  4. /*
  5. * 定义param渲染方法
  6. */
  7. class param extends AbstractAnnotationTag
  8. {
  9. public function tagName(): string
  10. {
  11. return 'param';
  12. }
  13. public function assetValue(?string $raw)
  14. {
  15. $list = explode(',',$raw);
  16. foreach ($list as $item){
  17. parse_str($item,$ret);
  18. foreach ($ret as $key => $value){
  19. $this->$key = trim($value," \t\n\r\0\x0B\"\'");
  20. }
  21. }
  22. }
  23. }
  24. /*
  25. * 定义timeout渲染方法
  26. */
  27. class timeout extends AbstractAnnotationTag
  28. {
  29. public $timeout;
  30. public function tagName(): string
  31. {
  32. return 'timeout';
  33. }
  34. public function assetValue(?string $raw)
  35. {
  36. $this->timeout = floatval($raw);
  37. }
  38. public function aliasMap(): array
  39. {
  40. return [
  41. static::class,
  42. "timeout_alias"
  43. ];
  44. }
  45. }
  46. class A
  47. {
  48. protected $a;
  49. /**
  50. * @param(name=a,type=string,value=2)
  51. * @param(name=b)
  52. * @timeout_Alias(0.5)
  53. * @fuck(easyswoole)
  54. * 这是我的其他说明啊啊啊啊啊
  55. */
  56. function test()
  57. {
  58. }
  59. }
  60. /**
  61. * 实例化渲染器,并注册要解析的渲染方法
  62. */
  63. $annotation = new Annotation();
  64. $ref = new \ReflectionClass(A::class);
  65. //不注册fuck 解析
  66. $annotation->addParserTag(new param());
  67. $annotation->addParserTag(new timeout());
  68. $list = $annotation->getClassMethodAnnotation($ref->getMethod('test'));
  69. foreach ($list['param'] as $item){
  70. var_dump((array)$item);
  71. }
  72. foreach ($list['timeout'] as $item){
  73. var_dump((array)$item);
  74. }

::: warning
注释每行前3个字符若存在@,说明该行为需要解析注释行,默认为非严格模式,未注册的tag信息不会解析,严格模式下,若无法解析则会抛出异常。 :::

默认注解解析工具

Easyswoole 自带的字符串解析工具为 EasySwoole\Annotation\ValueParser,支持格式如下单元测试代码所示:

  1. namespace EasySwoole\Annotation\Tests;
  2. use EasySwoole\Annotation\ValueParser;
  3. use PHPUnit\Framework\TestCase;
  4. class ValueParserTest extends TestCase
  5. {
  6. function testNormal()
  7. {
  8. $str = "int=1";
  9. $this->assertEquals([
  10. 'int'=>"1"
  11. ],ValueParser::parser($str));
  12. $str = "int=1,int2=2";
  13. $this->assertEquals([
  14. 'int'=>"1",
  15. 'int2'=>"2"
  16. ],ValueParser::parser($str));
  17. $str = "int=1,int2='2'";
  18. $this->assertEquals([
  19. 'int'=>"1",
  20. 'int2'=>"2"
  21. ],ValueParser::parser($str));
  22. }
  23. function testArray()
  24. {
  25. $str = "array={1,2,3}";
  26. $this->assertEquals([
  27. 'array'=>['1','2','3']
  28. ],ValueParser::parser($str));
  29. $str = "array={'1','2','3'}";
  30. $this->assertEquals([
  31. 'array'=>['1','2','3']
  32. ],ValueParser::parser($str));
  33. $str = "array={'1','2 , 3'}";
  34. $this->assertEquals([
  35. 'array'=>['1','2 , 3']
  36. ],ValueParser::parser($str));
  37. $str = 'array={"1","2","3"}';
  38. $this->assertEquals([
  39. 'array'=>['1','2','3']
  40. ],ValueParser::parser($str));
  41. $str = "array={1,2,3} ,array2={4,5,6}";
  42. $this->assertEquals([
  43. 'array'=>['1','2','3'],
  44. 'array2'=>['4','5','6']
  45. ],ValueParser::parser($str));
  46. }
  47. function testEval()
  48. {
  49. $str = 'time="eval(time() + 30)"';
  50. $this->assertEquals([
  51. 'time'=>time() + 30,
  52. ],ValueParser::parser($str));
  53. $str = 'time="eval(time() + 30)" , time2="eval(time() + 31)';
  54. $this->assertEquals([
  55. 'time'=>time() + 30,
  56. 'time2'=>time() + 31
  57. ],ValueParser::parser($str));
  58. $str = 'list="eval([1,2,3,4])"';
  59. $this->assertEquals([
  60. 'list'=>[1,2,3,4]
  61. ],ValueParser::parser($str));
  62. }
  63. function testArrayAndEval()
  64. {
  65. $str = 'array="{"1","2",eval(time() + 30)}"';
  66. $this->assertEquals([
  67. 'array'=>['1','2',time() + 30]
  68. ],ValueParser::parser($str));
  69. $str = 'array={"1","2",eval(time() + 30)},str="222"';
  70. $this->assertEquals([
  71. 'array'=>['1','2',time() + 30],
  72. "str"=>'222'
  73. ],ValueParser::parser($str));
  74. $str = "array={1,2,3},time=eval(time())";
  75. $this->assertEquals([
  76. 'array'=>['1','2','3'],
  77. 'time'=>time()
  78. ],ValueParser::parser($str));
  79. }
  80. function testStrMulti()
  81. {
  82. $str = 'mix="first|{1,2,3}|eval(time() + 3)"';
  83. $this->assertEquals([
  84. 'mix'=>['first',['1','2','3'],time() + 3]
  85. ],ValueParser::parser($str));
  86. }
  87. }

IDE支持

需要为PHPStorm安装”PHP Annotation”插件以提供注解自动提示能力,插件可以在PHPStorm中直接搜索安装,也可以前往Github下载安装

::: warning https://github.com/Haehnchen/idea-php-annotation-plugin :::

然后自己编写一个下面这样的注解提示类,重点在于使用@Annotation类注释,标记这是一个注解提示类,PHPStorm索引到该文件,就可以对类名和类的成员进行注解提示

  1. <?php
  2. namespace EasySwoole\Validate;
  3. /**
  4. * 注解标注文件
  5. * @Annotation
  6. * 需要向上方这样使用Annotation标记这是一个注解提示类
  7. */
  8. final class ValidateRule
  9. {
  10. /**
  11. * 括号内会提示这些字段
  12. * @var string
  13. */
  14. protected $name;
  15. /**
  16. * 括号内会提示这些字段
  17. * @var string
  18. */
  19. protected $column;
  20. /**
  21. * 括号内会提示这些字段
  22. * @var string
  23. */
  24. protected $alias;
  25. }

即可实现下面aaa方法的自动注解提示

  1. <?php
  2. use EasySwoole\Validate as Validate;
  3. class a
  4. {
  5. /**
  6. * @Validate\ValidateRule(column="name",alias="账号名称")
  7. */
  8. function aaa(){
  9. }
  10. }