@@ -134,6 +134,11 @@ class AnnotationManager
134
134
*/
135
135
private $ _cacheSeed = '' ;
136
136
137
+ /**
138
+ * Whether this version of PHP has support for traits.
139
+ */
140
+ private $ _traitsSupported ;
141
+
137
142
/**
138
143
* Initialize the Annotation Manager
139
144
*
@@ -145,6 +150,7 @@ public function __construct($cacheSeed = '')
145
150
$ this ->_usageAnnotation = new UsageAnnotation ();
146
151
$ this ->_usageAnnotation ->class = true ;
147
152
$ this ->_usageAnnotation ->inherited = true ;
153
+ $ this ->_traitsSupported = version_compare (PHP_VERSION , '5.4.0 ' , '>= ' );
148
154
}
149
155
150
156
/**
@@ -262,34 +268,52 @@ protected function getAnnotations($class_name, $member_type = self::MEMBER_CLASS
262
268
263
269
$ inherit = true ; // inherit parent annotations unless directed not to
264
270
265
- if (isset ($ file ) && isset ($ file ->data [$ key ])) {
266
- foreach ($ file ->data [$ key ] as $ spec ) {
267
- $ name = $ spec ['#name ' ]; // currently unused
268
- $ type = $ spec ['#type ' ];
271
+ if (isset ($ file )) {
272
+ if (isset ($ file ->data [$ key ])) {
273
+ foreach ($ file ->data [$ key ] as $ spec ) {
274
+ $ name = $ spec ['#name ' ]; // currently unused
275
+ $ type = $ spec ['#type ' ];
269
276
270
- unset($ spec ['#name ' ], $ spec ['#type ' ]);
277
+ unset($ spec ['#name ' ], $ spec ['#type ' ]);
271
278
272
- if (!class_exists ($ type , $ this ->autoload )) {
273
- throw new AnnotationException ("Annotation type ' {$ type }' does not exist " );
274
- }
279
+ if (!class_exists ($ type , $ this ->autoload )) {
280
+ throw new AnnotationException ("Annotation type ' {$ type }' does not exist " );
281
+ }
275
282
276
- $ annotation = new $ type ;
283
+ $ annotation = new $ type ;
277
284
278
- if (!($ annotation instanceof IAnnotation)) {
279
- throw new AnnotationException ("Annotation type ' {$ type }' does not implement the mandatory IAnnotation interface " );
280
- }
285
+ if (!($ annotation instanceof IAnnotation)) {
286
+ throw new AnnotationException ("Annotation type ' {$ type }' does not implement the mandatory IAnnotation interface " );
287
+ }
281
288
282
- if ($ annotation instanceof IAnnotationFileAware) {
283
- $ annotation ->setAnnotationFile ($ file );
284
- }
289
+ if ($ annotation instanceof IAnnotationFileAware) {
290
+ $ annotation ->setAnnotationFile ($ file );
291
+ }
285
292
286
- $ annotation ->initAnnotation ($ spec );
293
+ $ annotation ->initAnnotation ($ spec );
287
294
288
- $ annotations [] = $ annotation ;
289
- }
295
+ $ annotations [] = $ annotation ;
296
+ }
297
+
298
+ if ($ member_type === self ::MEMBER_CLASS ) {
299
+ $ classAnnotations = $ annotations ;
300
+ }
301
+ } else if ($ this ->_traitsSupported && $ member_name !== null ) {
302
+ $ traitAnnotations = array ();
303
+
304
+ if (isset ($ file ->traitMethodOverrides [$ class_name ][$ member_name ])) {
305
+ list ($ traitName , $ originalMemberName ) = $ file ->traitMethodOverrides [$ class_name ][$ member_name ];
306
+ $ traitAnnotations = $ this ->getAnnotations ($ traitName , $ member_type , $ originalMemberName );
307
+ } else {
308
+ foreach ($ reflection ->getTraitNames () as $ traitName ) {
309
+ if ($ this ->classHasMember ($ traitName , $ member_type , $ member_name )) {
310
+ $ traitAnnotations = $ this ->getAnnotations ($ traitName , $ member_type , $ member_name );
311
+ break ;
312
+ }
313
+ }
314
+ }
290
315
291
- if ($ member_type === self ::MEMBER_CLASS ) {
292
- $ classAnnotations = $ annotations ;
316
+ $ annotations = array_merge ($ traitAnnotations , $ annotations );
293
317
}
294
318
}
295
319
@@ -321,6 +345,25 @@ protected function getAnnotations($class_name, $member_type = self::MEMBER_CLASS
321
345
return $ this ->annotations [$ key ];
322
346
}
323
347
348
+ /**
349
+ * Determines whether a class or trait has the specified member.
350
+ *
351
+ * @param string $className The name of the class or trait to check
352
+ * @param string $memberType The type of member, e.g. "property" or "method"
353
+ * @param string $memberName The member name, e.g. "method" or "$property"
354
+ *
355
+ * @return bool whether class or trait has the specified member
356
+ */
357
+ protected function classHasMember ($ className , $ memberType , $ memberName )
358
+ {
359
+ if ($ memberType === self ::MEMBER_METHOD ) {
360
+ return method_exists ($ className , $ memberName );
361
+ } else if ($ memberType === self ::MEMBER_PROPERTY ) {
362
+ return property_exists ($ className , ltrim ($ memberName , '$ ' ));
363
+ }
364
+ return false ;
365
+ }
366
+
324
367
/**
325
368
* Validates the constraints (as defined by the UsageAnnotation of each annotation) of a
326
369
* list of annotations for a given type of member.
@@ -453,14 +496,14 @@ public function getClassAnnotations($class, $type = null)
453
496
$ class = ltrim ($ class , '\\' );
454
497
}
455
498
456
- if (!class_exists ($ class , $ this ->autoload )) {
457
- $ isTrait = function_exists ('trait_exists ' ) ? trait_exists ($ class , $ this ->autoload ) : false ;
458
-
459
- if (interface_exists ($ class , $ this ->autoload ) || $ isTrait ) {
460
- throw new AnnotationException ("Reading annotations from interface/trait ' {$ class }' is not supported " );
499
+ if (!class_exists ($ class , $ this ->autoload ) &&
500
+ !( function_exists ('trait_exists ' ) && trait_exists ($ class , $ this ->autoload ))
501
+ ) {
502
+ if (interface_exists ($ class , $ this ->autoload )) {
503
+ throw new AnnotationException ("Reading annotations from interface ' {$ class }' is not supported " );
461
504
}
462
505
463
- throw new AnnotationException ("Unable to read annotations from an undefined class ' {$ class }' " );
506
+ throw new AnnotationException ("Unable to read annotations from an undefined class/trait ' {$ class }' " );
464
507
}
465
508
466
509
if ($ type === null ) {
0 commit comments