jmacedo/php-simple-annotation

PHP 注解实现的一个简单直接且没有复杂性的方案。

2.0.1 2020-08-17 19:58 UTC

This package is auto-updated.

Last update: 2024-09-18 13:09:45 UTC


README

Latest Stable Version Total Downloads Latest Unstable Version License Build Status Scrutinizer Code Quality Code Coverage Code Intelligence Status

PHP 注解实现的一个简单直接且没有复杂性的方案。

需求

  • PHP >= 7.4.*
  • ext-json
  • ext-mbstring

安装

composer require jmacedo/php-simple-annotation

使用方法

以下类用于本文档的目的

namespace Examples;

/**
 * Class MyAnnotatedClass
 *
 * @package Examples
 * @metadata {"PI": 3.14, "name": "The name", "genre": "The genre", "age": "The age"}
 * @PI 3.14
 * @list ['item 1', 'item 2', 'item 3']
 * @uselessClass true
 */
class MyAnnotatedClass
{
    /**
     * @value 3.14
     * @var double
     * @description Math constant
     */
    const PI = 3.14;

    /** @var string */
    public $name;

    /** @var string */
    protected $genre;

    /** @var int */
    private $age;

    /**
     * MyAnnotatedClass constructor.
     *
     * @param string $name
     * @param string $genre
     * @param int $age
     */
    public function __construct(string $name = '', string $genre = '', int $age = 0)
    {
        $this->name = $name;
        $this->genre = $genre;
        $this->age = $age;
    }

    /**
     * A method that says "Hello!".
     *
     * @methodName sayHello
     * @emptyAnnotation
     */
    public function sayHello()
    {
        echo 'Hello!';
    }
}

你可以通过两种方式实例化 Annotation 类

  • 第一种
use SimpleAnnotation\Annotation;
use Examples\MyAnnotatedClass;

$annotation = new Annotation(MyAnnotatedClass::class);
// Or
$annotation = new Annotation('Examples\MyAnnotatedClass');
  • 第二种
use SimpleAnnotation\Annotation;
use Examples\MyAnnotatedClass;

$myAnnotatedClass = new MyAnnotatedClass();
$annotation = new Annotation($myAnnotatedClass);

获取类的注解

$classAnnotations = $annotation->getClassAnnotations();

var_dump($classAnnotations);
object(SimpleAnnotation\AnnotationParsed)[6]
  private 'properties' => 
    array (size=6)
      'package' => string 'Examples' (length=8)
      'metadata' => 
        object(stdClass)[5]
          public 'PI' => float 3.14
          public 'name' => string 'The name' (length=8)
          public 'genre' => string 'The genre' (length=9)
          public 'age' => string 'The age' (length=7)
      'PI' => float 3.14
      'list' => 
        array (size=3)
          0 => string 'item 1' (length=6)
          1 => string 'item 2' (length=6)
          2 => string 'item 3' (length=6)
      'uselessClass' => boolean true
      'anotherStringValue' => string 'my string' (length=9)

AnnotationParsed 类实现了 __get 和 __set 魔法方法,因此要访问注解键,只需访问属性即可

echo "PI value is:" . $classAnnotations->PI;
echo "PI is also available in: " . $classAnnotations->metadata->PI;

获取方法的注解

$methodsAnnotations = $annotation->getMethodsAnnotations();

var_dump($methodsAnnotations);
array (size=2)
  '__construct' => 
    object(SimpleAnnotation\AnnotationParsed)[9]
      private 'properties' => 
        array (size=1)
          'param' => 
            array (size=3)
              0 => string 'string $name' (length=12)
              1 => string 'string $genre' (length=13)
              2 => string 'int $age' (length=8)
  'sayHello' => 
    object(SimpleAnnotation\AnnotationParsed)[10]
      private 'properties' => 
        array (size=2)
          'methodName' => string 'sayHello' (length=8)
          'emptyAnnotation' => boolean true

对于特定方法

$sayHelloAnnotations = $annotation->getMethodAnnotations('sayHello');

var_dump($sayHelloAnnotations);
object(SimpleAnnotation\AnnotationParsed)[11]
  private 'properties' => 
    array (size=2)
      'methodName' => string 'sayHello' (length=8)
      'emptyAnnotation' => boolean true

获取属性的注解

$propertiesAnnotations = $annotation->getPropertiesAnnotations();

var_dump($propertiesAnnotations);
array (size=3)
  'name' => 
    object(SimpleAnnotation\AnnotationParsed)[12]
      private 'properties' => 
        array (size=1)
          'var' => string 'string' (length=6)
  'genre' => 
    object(SimpleAnnotation\AnnotationParsed)[13]
      private 'properties' => 
        array (size=1)
          'var' => string 'string' (length=6)
  'age' => 
    object(SimpleAnnotation\AnnotationParsed)[14]
      private 'properties' => 
        array (size=1)
          'var' => string 'int' (length=3)

对于特定属性

$nameAnnotations = $annotation->getPropertyAnnotations('name');

var_dump($nameAnnotations);
object(SimpleAnnotation\AnnotationParsed)[7]
  private 'properties' => 
    array (size=1)
      'var' => string 'string' (length=6)

就是这样

只需实例化 SimpleAnnotation\Annotation 类,调用方法,并使用你想要的类的注解值。

缓存

默认情况下,没有使用缓存,但有一个可用的缓存处理器,如果你需要的话

此缓存处理器使用文件方法,在我的某些简单基准测试中效果良好

$annotation = new Annotation(MyAnnotatedClass::class);
$start = microtime(true);
for ($i = 0; $i < $numberOfTimes; $i++) {
    $classAnnotation = $annotation->getClassAnnotations();
    $methodsAnnotations = $annotation->getMethodsAnnotations();
    $propertiesAnnotations = $annotation->getPropertiesAnnotations();
}
$end = microtime(true);
echo 'Time elapsed without cache: ' . ($end - $start) . "\n";

$cache = new SimpleAnnotation\Concerns\Cache\FileCache(__DIR__ . DIRECTORY_SEPARATOR . 'test.txt');
$annotation2 = new Annotation(MyAnnotatedClass::class, $cache);
$start2 = microtime(true);
for ($i = 0; $i < $numberOfTimes; $i++) {
    $classAnnotation = $annotation2->getClassAnnotations();
    $methodsAnnotations = $annotation2->getMethodsAnnotations();
    $propertiesAnnotations = $annotation2->getPropertiesAnnotations();
}
$end2 = microtime(true);
echo 'Time elapsed with cache: ' . ($end2 - $start2) . "\n";

对于 $numberOfTimes=100

Time elapsed without cache: 0.011738777160645
Time elapsed with cache: 0.00053501129150391

对于 $numberOfTimes=10000

Time elapsed without cache: 1.1012320518494
Time elapsed with cache: 0.055597066879272

对于 $numberOfTimes=100000

Time elapsed without cache: 11.216305971146
Time elapsed with cache: 0.53948402404785

SimpleAnnotation\Concerns\ParsedAnnotation 的具体实现必须实现 JsonSerializable 接口,以便 SimpleAnnotation\Concerns\Cache\FileCache 的实现能正常工作。

如果你使用此库的默认实现,你不必担心这一点。