1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpBoot\Annotation; |
4
|
|
|
use Doctrine\Common\Cache\ApcCache; |
5
|
|
|
use Doctrine\Common\Cache\Cache; |
6
|
|
|
use PhpBoot\Cache\CheckableCache; |
7
|
|
|
use PhpBoot\Cache\ClassModifiedChecker; |
8
|
|
|
use phpDocumentor\Reflection\DocBlock\DescriptionFactory; |
9
|
|
|
use phpDocumentor\Reflection\DocBlock\StandardTagFactory; |
10
|
|
|
use phpDocumentor\Reflection\DocBlock\Tag; |
11
|
|
|
use phpDocumentor\Reflection\DocBlock\Tags\Formatter; |
12
|
|
|
use phpDocumentor\Reflection\DocBlockFactory; |
13
|
|
|
use phpDocumentor\Reflection\FqsenResolver; |
14
|
|
|
use phpDocumentor\Reflection\TypeResolver; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* AnnotationEnabledTest |
18
|
|
|
*/ |
19
|
|
|
class AnnotationEnabledTest |
20
|
|
|
{ |
21
|
|
|
/** |
22
|
|
|
* testMethod |
23
|
|
|
*/ |
24
|
|
|
public function testMethod() |
25
|
|
|
{ |
26
|
|
|
|
27
|
|
|
} |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
class AnnotationTagsOutput implements Formatter |
31
|
|
|
{ |
32
|
|
|
/** |
33
|
|
|
* Formats a tag into a string representation according to a specific format, such as Markdown. |
34
|
|
|
* |
35
|
|
|
* @param Tag $tag |
36
|
|
|
* |
37
|
|
|
* @return string |
38
|
|
|
*/ |
39
|
5 |
|
public function format(Tag $tag) |
40
|
|
|
{ |
41
|
5 |
|
$this->tags[] = $tag; |
42
|
5 |
|
return strval($tag); |
43
|
|
|
} |
44
|
|
|
public $tags = []; |
45
|
|
|
} |
46
|
|
|
class AnnotationReader implements \ArrayAccess |
47
|
|
|
{ |
48
|
21 |
|
static public function createDocBlockFactory(){ |
49
|
21 |
|
$fqsenResolver = new FqsenResolver(); |
50
|
21 |
|
$tagFactory = new StandardTagFactory($fqsenResolver,[]); |
51
|
21 |
|
$descriptionFactory = new DescriptionFactory($tagFactory); |
52
|
21 |
|
$tagFactory->addService($descriptionFactory); |
53
|
21 |
|
$tagFactory->addService(new TypeResolver($fqsenResolver)); |
54
|
21 |
|
$docBlockFactory = new DocBlockFactory($descriptionFactory, $tagFactory); |
55
|
21 |
|
return $docBlockFactory; |
56
|
|
|
} |
57
|
|
|
|
58
|
21 |
|
static public function assertAnnotationEnabled() |
59
|
|
|
{ |
60
|
21 |
|
$rfl = new \ReflectionClass(AnnotationEnabledTest::class); |
61
|
21 |
|
!empty($rfl->getDocComment()) or \PhpBoot\abort('Annotation dose not work! If opcache is enable, please set opcache.save_comments=1 and opcache.load_comments=1'); |
62
|
21 |
|
} |
63
|
|
|
/** |
64
|
|
|
* load from class with local cache |
65
|
|
|
* TODO 增加 filter 能力 |
66
|
|
|
* @param string $className |
67
|
|
|
* @param Cache $localCache |
68
|
|
|
* @return object |
69
|
|
|
*/ |
70
|
21 |
|
static public function read($className, Cache $localCache = null) |
71
|
|
|
{ |
72
|
21 |
|
self::assertAnnotationEnabled(); |
73
|
21 |
|
$rfl = new \ReflectionClass($className) or \PhpBoot\abort("load class $className failed"); |
74
|
21 |
|
$fileName = $rfl->getFileName(); |
75
|
21 |
|
$key = str_replace('\\','.',self::class).md5($fileName.$className); |
76
|
21 |
|
$oldData = null; |
77
|
21 |
|
$cache = new CheckableCache($localCache?:new ApcCache()); |
|
|
|
|
78
|
21 |
|
$res = $cache->get('ann:'.$key, null, $oldData, false); |
79
|
21 |
|
if($res === null){ |
80
|
|
|
try{ |
81
|
21 |
|
$meta = self::readWithoutCache($className); |
82
|
21 |
|
$cache->set($key, $meta, 0, $fileName?new ClassModifiedChecker($className):null); |
83
|
21 |
|
return $meta; |
84
|
1 |
|
}catch (\Exception $e){ |
85
|
|
|
$cache->set($key, $e->getMessage(), 0, $fileName?new ClassModifiedChecker($className):null); |
86
|
|
|
throw $e; |
87
|
1 |
|
} |
88
|
|
|
}elseif(is_string($res)){ |
89
|
|
|
\PhpBoot\abort($res); |
90
|
|
|
}else{ |
91
|
|
|
return $res; |
92
|
|
|
} |
93
|
|
|
} |
94
|
|
|
/** |
95
|
|
|
* @param $className |
96
|
|
|
* @return self |
97
|
|
|
*/ |
98
|
21 |
|
static function readWithoutCache($className) |
99
|
|
|
{ |
100
|
21 |
|
$reader = new self(); |
101
|
|
|
|
102
|
21 |
|
$rfl = new \ReflectionClass($className); |
103
|
21 |
|
$reader->class = self::readAnnotationBlock($rfl->getDocComment()); |
104
|
21 |
|
$reader->class->name = $className; |
105
|
|
|
|
106
|
|
|
//method annotations |
107
|
21 |
|
foreach ($rfl->getMethods() as $i){ |
108
|
17 |
|
$block = self::readAnnotationBlock($i->getDocComment()); |
109
|
17 |
|
$block->name = $i->getName(); |
|
|
|
|
110
|
17 |
|
$reader->methods[$i->getName()]=$block; |
|
|
|
|
111
|
21 |
|
} |
112
|
|
|
//property annotations |
113
|
21 |
View Code Duplication |
foreach ($rfl->getProperties() as $i){ |
|
|
|
|
114
|
20 |
|
if ($i->isStatic()) { |
115
|
16 |
|
continue; |
116
|
|
|
} |
117
|
20 |
|
$block = self::readAnnotationBlock($i->getDocComment()); |
118
|
20 |
|
$block->name = $i->getName(); |
119
|
20 |
|
$reader->properties[$i->getName()]=$block; |
120
|
21 |
|
} |
121
|
21 |
|
while ($rfl = $rfl->getParentClass()) { |
122
|
1 |
View Code Duplication |
foreach ($rfl->getProperties(\ReflectionProperty::IS_PRIVATE) as $i) { |
|
|
|
|
123
|
1 |
|
if ($i->isStatic()) { |
124
|
|
|
continue; |
125
|
|
|
} |
126
|
1 |
|
$block = self::readAnnotationBlock($i->getDocComment()); |
127
|
1 |
|
$block->name = $i->getName(); |
128
|
1 |
|
$reader->properties[$i->getName()]=$block; |
129
|
1 |
|
} |
130
|
1 |
|
} |
131
|
21 |
|
return $reader; |
132
|
|
|
} |
133
|
|
|
|
134
|
21 |
|
static private function readAnnotationBlock($doc) |
135
|
|
|
{ |
136
|
21 |
|
$annBlock = new AnnotationBlock(); |
137
|
21 |
|
if(empty($doc)){ |
138
|
20 |
|
return $annBlock; |
139
|
|
|
} |
140
|
21 |
|
$docFactory = AnnotationReader::createDocBlockFactory(); |
141
|
21 |
|
$docBlock = $docFactory->create($doc); |
142
|
21 |
|
$annBlock->summary = $docBlock->getSummary(); |
143
|
21 |
|
$annBlock->description = strval($docBlock->getDescription()); |
144
|
21 |
|
$annBlock->children = []; |
145
|
21 |
|
$tags = $docBlock->getTags(); |
146
|
21 |
|
foreach ($tags as $tag) { |
147
|
21 |
|
$annTag = new AnnotationTag(); |
148
|
21 |
|
$desc = $tag->getDescription(); |
149
|
21 |
|
$annTag->parent = $annBlock; |
150
|
21 |
|
$annTag->description = strval($desc); |
151
|
21 |
|
$annTag->name = $tag->getName(); |
152
|
21 |
|
$annTag->children=[]; |
153
|
21 |
|
if($desc){ |
154
|
21 |
|
$output = new AnnotationTagsOutput(); |
155
|
21 |
|
$desc->render($output); |
156
|
21 |
|
foreach ($output->tags as $child) { |
157
|
5 |
|
$childTag = new AnnotationTag(); |
158
|
5 |
|
$childTag->parent = $annTag; |
|
|
|
|
159
|
5 |
|
$childTag->name = $child->getName(); |
160
|
5 |
|
$childTag->description = strval($child->getDescription()); |
161
|
5 |
|
$annTag->children[] = $childTag; |
162
|
21 |
|
} |
163
|
21 |
|
} |
164
|
21 |
|
$annBlock->children[] = $annTag; |
165
|
21 |
|
} |
166
|
21 |
|
return $annBlock; |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
/** |
170
|
|
|
* @var AnnotationBlock |
171
|
|
|
*/ |
172
|
|
|
public $class; |
173
|
|
|
/** |
174
|
|
|
* @var AnnotationBlock[] |
175
|
|
|
*/ |
176
|
|
|
|
177
|
|
|
public $methods=[]; |
178
|
|
|
/** |
179
|
|
|
* @var AnnotationBlock[] |
180
|
|
|
*/ |
181
|
|
|
public $properties=[]; |
182
|
|
|
|
183
|
21 |
|
public function offsetExists($offset) |
184
|
|
|
{ |
185
|
21 |
|
return isset($this->$offset); |
186
|
|
|
} |
187
|
|
|
|
188
|
21 |
|
public function offsetGet($offset) |
189
|
|
|
{ |
190
|
21 |
|
return $this->$offset; |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
public function offsetSet($offset, $value) |
194
|
|
|
{ |
195
|
|
|
$this->$offset = $value; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
public function offsetUnset($offset) |
199
|
|
|
{ |
200
|
|
|
unset($this->$offset); |
201
|
|
|
} |
202
|
|
|
} |
This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.