Index: ext/reflection/php_reflection.c
===================================================================
--- ext/reflection/php_reflection.c	(revision 309164)
+++ ext/reflection/php_reflection.c	(working copy)
@@ -41,6 +41,10 @@
 #include "zend_closures.h"
 #include "zend_extensions.h"
 
+#define ANNOTATION_INHERITED (1<<0) 
+#define ANNOTATION_DECLARED  (1<<1)
+#define ANNOTATION_ALL      ANNOTATION_INHERITED | ANNOTATION_DECLARED
+
 #define reflection_update_property(object, name, value) do { \
 		zval *member; \
 		MAKE_STD_ZVAL(member); \
@@ -63,6 +67,8 @@
 PHPAPI zend_class_entry *reflection_property_ptr;
 PHPAPI zend_class_entry *reflection_extension_ptr;
 PHPAPI zend_class_entry *reflection_zend_extension_ptr;
+PHPAPI zend_class_entry *reflection_annotation_ptr;
+PHPAPI zend_class_entry *reflection_annotation_inherited_ptr;
 
 #if MBO_0
 ZEND_BEGIN_MODULE_GLOBALS(reflection)
@@ -111,6 +117,22 @@
 #define REGISTER_REFLECTION_CLASS_CONST_LONG(class_name, const_name, value)                                        \
 	zend_declare_class_constant_long(reflection_ ## class_name ## _ptr, const_name, sizeof(const_name)-1, (long)value TSRMLS_CC);
 
+#define FETCH_ANNOTATION_CE(ace, aname, alength) \
+		ace = zend_fetch_class(aname, alength, ZEND_FETCH_CLASS_AUTO TSRMLS_CC); \
+		if (!ace) { \
+			php_error_docref(NULL TSRMLS_CC, E_ERROR, "Could not find class '%s'", aname); \
+		} else if ((ace->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) != 0) { \
+			if (ace->ce_flags & ZEND_ACC_INTERFACE) { \
+				php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot instantiate interface %s", ace->name); \
+			} else if ((ace->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { \
+				php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot instantiate trait %s", ace->name); \
+			} else { \
+				php_error_docref(NULL TSRMLS_CC, E_ERROR, "Cannot instantiate abstract class %s", ace->name); \
+			} \
+		} else if (!instanceof_function(ace, reflection_annotation_ptr TSRMLS_CC)) { \
+			php_error_docref(NULL TSRMLS_CC, E_ERROR, "'%s' must extend '%s' to act as an annotation", ace->name, reflection_annotation_ptr->name); \
+		} 
+
 /* {{{ Smart string functions */
 typedef struct _string {
 	char *string;
@@ -212,9 +234,15 @@
 	unsigned int ignore_visibility:1;
 } reflection_object;
 
+/* Struct for reflection annotation */
+typedef struct _annotation_reflection_object {
+	zend_object std;
+} annotation_reflection_object;
+
 /* }}} */
 
 static zend_object_handlers reflection_object_handlers;
+static zend_object_handlers reflection_annotation_handlers;
 
 static void _default_get_entry(zval *object, char *name, int name_len, zval *return_value TSRMLS_DC) /* {{{ */
 {
@@ -1797,6 +1825,75 @@
 }
 /* }}} */
 
+/*  {{{ proto public array ReflectionFunction::getAnnotations() 
+	Returns all annotations for this function (or an empty array if the function has no annotation). */
+ZEND_METHOD(reflection_function, getAnnotations)
+{
+	reflection_object *intern;
+	zend_function *fptr;
+
+	if (zend_parse_parameters_none() == FAILURE) {
+		return;
+	}
+	GET_REFLECTION_OBJECT_PTR(fptr);
+	array_init(return_value);
+
+	if (intern->ce == fptr->common.scope && fptr->type == ZEND_USER_FUNCTION && fptr->op_array.annotations) {
+		reflection_add_declared_annotations(return_value, fptr->op_array.annotations, getThis() TSRMLS_CC);
+	}
+}
+/* }}} */
+
+/* {{{ proto public Annotation ReflectionFunction::getAnnotation(string name) 
+   Return the annotation of the specified type if present, else null */
+ZEND_METHOD(reflection_function, getAnnotation)
+{
+	reflection_object *intern;
+	zend_function *fptr;
+	zend_annotation **annotation;
+	char *name = NULL;
+	int name_length = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_length) == FAILURE) {
+		return;
+	} 
+
+	GET_REFLECTION_OBJECT_PTR(fptr);
+	zend_str_tolower(name, name_length);
+
+	if (intern->ce == fptr->common.scope && fptr->type == ZEND_USER_FUNCTION && fptr->op_array.annotations
+			&& zend_hash_find(fptr->op_array.annotations, name, name_length +1, (void **) &annotation) == SUCCESS) {
+		reflection_create_annotation(return_value, *annotation, getThis(), NULL TSRMLS_CC);
+	}   
+
+}
+/* }}} */
+
+/* {{{ proto public boolean ReflectionFunction::hasAnnotation(string name) 
+   Return true if the annotation of the specified type is present, else false */
+ZEND_METHOD(reflection_function, hasAnnotation)
+{
+	reflection_object *intern;
+	zend_function *fptr;
+	char *name = NULL;
+	int name_length = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_length) == FAILURE) {
+		return;
+	}   
+	
+	GET_REFLECTION_OBJECT_PTR(fptr);
+	zend_str_tolower(name, name_length);
+
+	if (intern->ce == fptr->common.scope && fptr->type == ZEND_USER_FUNCTION && fptr->op_array.annotations 
+			&& zend_symtable_exists(fptr->op_array.annotations, name, name_length + 1)) {
+		RETURN_TRUE;   
+	} else {   
+		RETURN_FALSE;
+	}   
+}
+/* }}} */
+
 /* {{{ proto public array ReflectionFunction::getStaticVariables()
    Returns an associative array containing this function's static variables and their values */
 ZEND_METHOD(reflection_function, getStaticVariables)
@@ -2640,6 +2737,73 @@
 }
 /* }}} */
 
+/*  {{{ proto public array ReflectionParameter::getAnnotations() 
+    Returns all annotations for this parameter (or an empty array if the function has no annotation). */
+ZEND_METHOD(reflection_parameter, getAnnotations)
+{
+	reflection_object *intern;
+	parameter_reference *param;
+
+	if (zend_parse_parameters_none() == FAILURE) {
+		return;
+	}
+	GET_REFLECTION_OBJECT_PTR(param);
+	array_init(return_value);
+	if (param->arg_info->annotations) {
+		reflection_add_declared_annotations(return_value, param->arg_info->annotations, getThis() TSRMLS_CC);
+	}
+}
+/* }}} */
+
+/* {{{ proto public Annotation ReflectionParameter::getAnnotation(string name) 
+   Return the annotation of the specified type if present, else null */
+ZEND_METHOD(reflection_parameter, getAnnotation)
+{
+	reflection_object *intern;
+	parameter_reference *param;
+
+	zend_annotation **annotation;
+	char *name = NULL;
+	int name_length = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_length) == FAILURE) {
+		return;
+	}
+
+	GET_REFLECTION_OBJECT_PTR(param);
+	zend_str_tolower(name, name_length);
+
+	if (param->arg_info->annotations
+			&& zend_hash_find(param->arg_info->annotations, name, name_length +1, (void **) &annotation) == SUCCESS) {
+		reflection_create_annotation(return_value, *annotation, getThis(), NULL TSRMLS_CC);
+	}
+}
+/* }}} */
+
+/* {{{ proto public boolean ReflectionParameter::hasAnnotation(string name) 
+   Return true if the annotation of the specified type is present, else false */
+ZEND_METHOD(reflection_parameter, hasAnnotation)
+{
+    reflection_object *intern;
+    parameter_reference *param;
+    char *name = NULL;
+    int name_length = 0;
+
+    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_length) == FAILURE) {
+        return;
+    }
+
+    GET_REFLECTION_OBJECT_PTR(param);
+    zend_str_tolower(name, name_length);
+
+    if (param->arg_info->annotations && zend_symtable_exists(param->arg_info->annotations, name, name_length + 1)) {
+        RETURN_TRUE;
+    } else {
+        RETURN_FALSE;
+    }
+}
+/* }}} */
+
 /* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
    Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
 ZEND_METHOD(reflection_method, export)
@@ -3605,6 +3769,105 @@
 }
 /* }}} */
 
+/*  {{{ proto public array ReflectionClass::getAnnotations([long $filter]) 
+	Returns all annotations for this class (or an empty array if the class has no annotation). */
+ZEND_METHOD(reflection_class, getAnnotations)
+{
+	reflection_object *intern;
+	zend_class_entry *ce;
+	long filter = ANNOTATION_ALL;
+
+	METHOD_NOTSTATIC(reflection_class_ptr);
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &filter) == FAILURE) {
+		return;
+	}
+	
+	GET_REFLECTION_OBJECT_PTR(ce);
+	array_init(return_value);
+
+	if (filter & ANNOTATION_DECLARED && ce->type == ZEND_USER_CLASS && ce->info.user.annotations) {
+		reflection_add_declared_annotations(return_value, ce->info.user.annotations, getThis() TSRMLS_CC);
+	}
+
+	if (filter & ANNOTATION_INHERITED) {
+		while((ce = ce->parent)) {
+			if (ce->type == ZEND_USER_CLASS && ce->info.user.annotations) {
+				reflection_add_inherited_annotations(return_value, ce->info.user.annotations, getThis() TSRMLS_CC);
+			}
+		}
+	}
+}
+/* }}} */
+
+/* {{{ proto public Annotation ReflectionClass::getAnnotation(string name [, long $filter]) 
+   Return the annotation of the specified type if present, else null */
+ZEND_METHOD(reflection_class, getAnnotation)
+{
+	reflection_object *intern;
+	zend_class_entry *ce;
+	zend_annotation **annotation_ref_ref;
+	char *name = NULL;
+	int name_length = 0;
+	long filter = ANNOTATION_ALL;
+
+	METHOD_NOTSTATIC(reflection_class_ptr);
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &name, &name_length, &filter) == FAILURE) {
+		return;
+	}   
+
+	GET_REFLECTION_OBJECT_PTR(ce);
+	zend_str_tolower(name, name_length);
+
+	if (filter & ANNOTATION_DECLARED && ce->type == ZEND_USER_CLASS && ce->info.user.annotations && zend_hash_find(ce->info.user.annotations, name, name_length +1, (void **) &annotation_ref_ref) == SUCCESS) {
+		reflection_create_annotation(return_value, *annotation_ref_ref, getThis(), NULL TSRMLS_CC);
+		return;
+	}
+	
+	if (filter & ANNOTATION_INHERITED) {
+		while((ce = ce->parent)) {
+			if (ce->type == ZEND_USER_CLASS && ce->info.user.annotations && reflection_get_inherited_annotation(ce->info.user.annotations, name, name_length, getThis(), return_value TSRMLS_CC) == SUCCESS) {
+				return;
+			}
+		}
+	}
+}
+/* }}} */
+
+/* {{{ proto public boolean ReflectionClass::hasAnnotation(string name [, long $filter]) 
+   Return true if the annotation of the specified type is present, else false */
+ZEND_METHOD(reflection_class, hasAnnotation)
+{
+	reflection_object *intern;
+	zend_class_entry *ce;
+	char *name = NULL;
+	int name_length = 0;
+	long filter = ANNOTATION_ALL;
+
+	METHOD_NOTSTATIC(reflection_class_ptr);
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &name, &name_length, &filter) == FAILURE) {
+		return;
+	}
+
+	GET_REFLECTION_OBJECT_PTR(ce);
+	zend_str_tolower(name, name_length);
+
+	if (filter & ANNOTATION_DECLARED) {
+		if (ce->type == ZEND_USER_CLASS && ce->info.user.annotations && zend_symtable_exists(ce->info.user.annotations, name, name_length + 1)) {
+			RETURN_TRUE;
+		} 
+	}
+
+	if (filter & ANNOTATION_INHERITED) {
+		while((ce = ce->parent)) {
+			if (ce->type == ZEND_USER_CLASS && ce->info.user.annotations && reflection_get_inherited_annotation(ce->info.user.annotations, name, name_length, getThis(), NULL TSRMLS_CC) == SUCCESS) {
+				RETURN_TRUE;	
+			}
+		}
+	}
+	RETURN_FALSE;
+}
+/* }}} */
+
 /* {{{ proto public ReflectionMethod ReflectionClass::getConstructor()
    Returns the class' constructor if there is one, NULL otherwise */
 ZEND_METHOD(reflection_class, getConstructor)
@@ -5069,6 +5332,72 @@
 }
 /* }}} */
 
+/*  {{{ proto public array ReflectionProperty::getAnnotations() 
+	Returns all annotations for this property (or an empty array if the property has no annotation). */
+ZEND_METHOD(reflection_property, getAnnotations)
+{
+	reflection_object *intern;
+	property_reference *ref;
+
+	if (zend_parse_parameters_none() == FAILURE) {
+		return;
+	}
+	GET_REFLECTION_OBJECT_PTR(ref);
+	array_init(return_value);
+
+	if (ref->prop.annotations) {
+		reflection_add_declared_annotations(return_value, ref->prop.annotations, getThis() TSRMLS_CC);
+	}
+}
+/* }}} */
+
+/* {{{ proto public Annotation ReflectionProperty::getAnnotation(string name) 
+   Return the annotation of the specified type if present, else null */
+ZEND_METHOD(reflection_property, getAnnotation)
+{
+	reflection_object *intern;
+	property_reference *ref;
+	zend_annotation **annotation;
+	char *name = NULL;
+	int name_length = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_length) == FAILURE) {
+		return;
+	}
+
+	GET_REFLECTION_OBJECT_PTR(ref);
+	zend_str_tolower(name, name_length);
+
+	if (ref->prop.annotations && zend_hash_find(ref->prop.annotations, name, name_length +1, (void **) &annotation) == SUCCESS) {
+		reflection_create_annotation(return_value, *annotation, getThis(), NULL TSRMLS_CC);
+	}   
+}
+/* }}} */
+
+/* {{{ proto public boolean ReflectionProperty::hasAnnotation(string name) 
+   Return true if the annotation of the specified type is present, else false */
+ZEND_METHOD(reflection_property, hasAnnotation)
+{
+	reflection_object *intern;
+	property_reference *ref;
+	char *name = NULL;
+	int name_length = 0;
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_length) == FAILURE) {
+		return;
+	}
+
+	GET_REFLECTION_OBJECT_PTR(ref);
+	zend_str_tolower(name, name_length);
+
+	if (ref->prop.annotations && zend_symtable_exists(ref->prop.annotations, name, name_length + 1)) {
+		RETURN_TRUE;
+	} else {
+		RETURN_FALSE;
+	}
+}
+/* }}} */
+
 /* {{{ proto public int ReflectionProperty::setAccessible(bool visible)
    Sets whether non-public properties can be requested */
 ZEND_METHOD(reflection_property, setAccessible)
@@ -5589,6 +5918,293 @@
 }
 /* }}} */
 
+void reflection_create_annotation_parameters(zval *params, HashTable *ht, zval *reflector TSRMLS_DC) /* {{{ */
+{
+	zend_annotation_value **value_ref_ref, *value_ref;
+	zval *val;
+	int constant_index;
+
+	char *string_key;
+	uint str_key_len;
+	ulong num_key;
+
+	zval const_value;
+	char *colon;
+
+	array_init(params);
+
+	if (ht) {
+		zend_hash_internal_pointer_reset(ht);
+		while (zend_hash_get_current_data(ht, (void **) &value_ref_ref) == SUCCESS) {
+			value_ref = *value_ref_ref;
+
+			if (value_ref->type & IS_CONSTANT_INDEX) {
+				value_ref->type &= ~IS_CONSTANT_INDEX;
+				constant_index = 1;
+			} else {
+				constant_index = 0;
+			}
+
+			switch(value_ref->type) {
+				case ZEND_ANNOTATION_ZVAL:
+					if ((Z_TYPE_P(value_ref->value.zval) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT ||
+							Z_TYPE_P(value_ref->value.zval)==IS_CONSTANT_ARRAY) {
+						char *str = Z_STRVAL_P(value_ref->value.zval);
+						zval_update_constant(&value_ref->value.zval, 0 TSRMLS_CC);
+						efree(str);
+					} 
+					val = value_ref->value.zval;
+					Z_ADDREF_P(val);
+					break;
+				case ZEND_ANNOTATION_HASH:
+					MAKE_STD_ZVAL(val);
+					reflection_create_annotation_parameters(val, value_ref->value.ht, reflector TSRMLS_CC);
+					break;
+				case ZEND_ANNOTATION_ANNO:
+					MAKE_STD_ZVAL(val);
+					reflection_create_annotation(val, value_ref->value.annotation, reflector, NULL TSRMLS_CC);
+					break;
+			}
+
+			if (constant_index) {
+				value_ref->type |= IS_CONSTANT_INDEX;
+			}
+
+			switch (zend_hash_get_current_key_ex(ht, &string_key, &str_key_len, &num_key, 0, NULL)) {
+				case HASH_KEY_IS_STRING:
+					if (constant_index) {
+						if (!zend_get_constant_ex(string_key, str_key_len - 3, &const_value, NULL, string_key[str_key_len - 2] TSRMLS_CC)) {
+							char *actual, *save = string_key;
+							if ((colon = zend_memrchr(string_key, ':', str_key_len - 3))) {
+								zend_error(E_ERROR, "Undefined class constant '%s'", string_key);
+								str_key_len -= ((colon - string_key) + 1);
+								string_key = colon;
+							} else {
+								if (string_key[str_key_len - 2] & IS_CONSTANT_UNQUALIFIED) {
+									if ((actual = (char *)zend_memrchr(string_key, '\\', str_key_len - 3))) {
+										actual++;
+										str_key_len -= (actual - string_key);
+										string_key = actual;
+									}
+								}
+								if (string_key[0] == '\\') {
+									++string_key;
+									--str_key_len;
+								}
+								if (save[0] == '\\') {
+									++save;
+								}
+								if ((string_key[str_key_len - 2] & IS_CONSTANT_UNQUALIFIED) == 0) {
+									zend_error(E_ERROR, "Undefined constant '%s'", save);
+								}
+								zend_error(E_NOTICE, "Use of undefined constant %s - assumed '%s'", string_key, string_key);
+							}
+							ZVAL_STRINGL(&const_value, string_key, str_key_len-3, 1);
+						}
+
+						switch (Z_TYPE(const_value)) {
+							case IS_STRING:
+								zend_symtable_update(Z_ARRVAL_P(params), Z_STRVAL(const_value), Z_STRLEN(const_value) + 1, &val, sizeof(val), NULL);
+								break;
+							case IS_BOOL:
+							case IS_LONG:
+								zend_hash_index_update(Z_ARRVAL_P(params), Z_LVAL(const_value), &val, sizeof(val), NULL);
+								break;
+							case IS_DOUBLE:
+								zend_hash_index_update(Z_ARRVAL_P(params), zend_dval_to_lval(Z_DVAL(const_value)), &val, sizeof(val), NULL);
+								break;
+							case IS_NULL:
+								zend_symtable_update(Z_ARRVAL_P(params), "", 1, &val, sizeof(val), NULL);
+								break;
+						}
+						zval_dtor(&const_value);
+					} else {
+						zend_symtable_update(Z_ARRVAL_P(params), string_key, str_key_len, &val, sizeof(val), NULL);
+					}
+					break;
+				case HASH_KEY_IS_LONG:
+					zend_hash_index_update(Z_ARRVAL_P(params), num_key, &val, sizeof(val), NULL);
+					break;
+			}
+			zend_hash_move_forward(ht);
+		}
+	}
+}
+/* }}} */
+
+void reflection_create_annotation(zval *res, zend_annotation *annotation, zval *reflector, zend_class_entry *ce TSRMLS_DC) /* {{{ */
+{
+	zend_fcall_info fci;
+	zend_fcall_info_cache fcc;
+	zval *retval_ptr;
+
+	if (!annotation->instance) {
+
+		if (ce == NULL) {
+			FETCH_ANNOTATION_CE(ce, annotation->annotation_name, annotation->aname_len);
+		}
+
+		MAKE_STD_ZVAL(annotation->instance);
+		object_init_ex(annotation->instance, ce);
+
+		if (ce->constructor) {
+			zval *params = NULL;
+			MAKE_STD_ZVAL(params);
+
+			reflection_create_annotation_parameters(params, annotation->values, reflector TSRMLS_CC);
+
+			fci.size = sizeof(fci);
+			fci.function_table = &ce->function_table;
+			fci.function_name = NULL;
+			fci.symbol_table = NULL;
+
+			fci.object_ptr = annotation->instance;
+			fci.retval_ptr_ptr = &retval_ptr;
+
+			fci.param_count = 2;
+			fci.params = (zval***) safe_emalloc(sizeof(zval*), 2, 0);
+			fci.params[0] = &reflector;
+			fci.params[1] = &params;
+
+			fcc.initialized = 1;
+			fcc.function_handler = ce->constructor;
+			fcc.calling_scope = EG(scope);
+			fcc.called_scope = Z_OBJCE_P(annotation->instance);
+			fcc.object_ptr = annotation->instance;
+
+			if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) {
+				zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name);
+			} else {
+				if (retval_ptr) {
+					zval_ptr_dtor(&retval_ptr);
+				}
+			}
+			if (fci.params) {
+				efree(fci.params);
+			}
+			zval_ptr_dtor(&params);
+		}
+	}
+
+	*res = *annotation->instance;
+	zval_copy_ctor(res);
+	INIT_PZVAL(res);
+}
+/* }}} */
+
+void reflection_add_declared_annotations(zval *res, HashTable *annotations, zval *reflector TSRMLS_DC) /* {{{ */
+{
+	zend_annotation **annotation_ref_ref, *annotation_ref;
+	zval *annotation_zval;
+
+	for (zend_hash_internal_pointer_reset(annotations); zend_hash_get_current_data(annotations, (void **)&annotation_ref_ref) == SUCCESS; zend_hash_move_forward(annotations)) {
+		MAKE_STD_ZVAL(annotation_zval);
+		annotation_ref = *annotation_ref_ref;
+		reflection_create_annotation(annotation_zval, annotation_ref, reflector, NULL TSRMLS_CC);
+		add_assoc_zval_ex(res, annotation_ref->annotation_name, annotation_ref->aname_len +1, annotation_zval);
+	}
+}
+/* }}} */
+
+void reflection_add_inherited_annotations(zval *res, HashTable *annotations, zval *reflector TSRMLS_DC) /* {{{ */
+{
+	zend_annotation **annotation_ref_ref, *annotation_ref;
+	zend_class_entry *ce = NULL;
+	zval *annotation_zval;
+
+	for (zend_hash_internal_pointer_reset(annotations);
+			zend_hash_get_current_data(annotations, (void **)&annotation_ref_ref) == SUCCESS; zend_hash_move_forward(annotations)) {
+
+		annotation_ref = *annotation_ref_ref;
+		if (zend_symtable_exists(Z_ARRVAL_P(res), annotation_ref->annotation_name, annotation_ref->aname_len+ 1)) {
+			continue;
+		}
+
+		FETCH_ANNOTATION_CE(ce, annotation_ref->annotation_name, annotation_ref->aname_len);
+
+		if (ce->type == ZEND_USER_CLASS && ce->info.user.annotations && 
+				zend_symtable_exists(ce->info.user.annotations, "inherited", sizeof("inherited"))) {
+			MAKE_STD_ZVAL(annotation_zval);
+			reflection_create_annotation(annotation_zval, annotation_ref, reflector, ce TSRMLS_CC);
+			add_assoc_zval_ex(res, annotation_ref->annotation_name, annotation_ref->aname_len +1, annotation_zval);
+		}
+	}
+}
+/* }}} */
+
+int reflection_get_inherited_annotation(HashTable *annotations, const char *name, const uint nameLength, zval *reflector, zval *res TSRMLS_DC) /* {{{ */
+{
+	zend_class_entry *annotation_ce;
+	zend_annotation **annotation_ref_ref, *annotation_ref;
+	if (zend_hash_find(annotations, name, nameLength+1, (void **) &annotation_ref_ref) == SUCCESS) {
+		
+		annotation_ref = *annotation_ref_ref;
+
+		FETCH_ANNOTATION_CE(annotation_ce, annotation_ref->annotation_name, annotation_ref->aname_len);
+
+		if (annotation_ce->type == ZEND_USER_CLASS && annotation_ce->info.user.annotations && zend_symtable_exists(annotation_ce->info.user.annotations, "inherited", sizeof("inherited"))) {
+			if (res != NULL) {
+				reflection_create_annotation(res, annotation_ref, reflector, annotation_ce TSRMLS_CC);
+			}
+			return SUCCESS;
+		}   
+	}
+	return FAILURE;
+}
+/* }}} */
+
+/* {{{ proto public void ReflectionAnnotation::__construct(array $data)
+	Constructor*/
+ZEND_METHOD(reflection_annotation, __construct)
+{
+	zval *reflector = NULL;
+	zval *data = NULL;
+	zval *object = getThis();
+
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|a!", &reflector, reflector_ptr, &data) == FAILURE) {
+		return;
+	}
+
+	if (data) {
+		zend_merge_properties(object, Z_ARRVAL_P(data), 0 TSRMLS_CC);
+	}
+}
+/* }}} */
+
+/** {{{ proto public mixed ReflectionAnnotation::getValue(void) 
+ */
+ZEND_METHOD(reflection_annotation, getValue)
+{
+	zval *value = zend_read_property(Z_OBJCE_P(getThis()), getThis(), "value", sizeof("value")-1, 1 TSRMLS_CC);
+	*return_value = *value;
+	zval_copy_ctor(return_value);
+	INIT_PZVAL(return_value);
+}
+/* }}} */
+
+static void reflection_annotation_free_storage(annotation_reflection_object *intern TSRMLS_DC) /* {{{ */
+{
+	zend_object_std_dtor(&intern->std TSRMLS_CC);
+	efree(intern);
+}
+/* }}} */
+
+static zend_object_value reflection_annotation_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */
+{
+	zend_object_value object;
+	annotation_reflection_object *intern;
+
+	intern = (annotation_reflection_object *) ecalloc(1, sizeof(annotation_reflection_object));
+
+	zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+	object_properties_init(&intern->std, class_type);
+
+	object.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) reflection_annotation_free_storage, NULL TSRMLS_CC);
+	object.handlers = &reflection_annotation_handlers;
+	return object;
+}
+/* }}} */
+
 /* {{{ method tables */
 static const zend_function_entry reflection_exception_functions[] = {
 	{NULL, NULL, NULL}
@@ -5636,6 +6252,10 @@
 	ZEND_ARG_ARRAY_INFO(0, args, 0)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO(arginfo_reflection_function_getAnnotation, 0)
+	ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO()
+
 static const zend_function_entry reflection_function_abstract_functions[] = {
 	ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
 	PHP_ABSTRACT_ME(reflection_function, __toString, arginfo_reflection__void)
@@ -5646,6 +6266,9 @@
 	ZEND_ME(reflection_function, isUserDefined, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_function, getClosureThis, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_function, getDocComment, arginfo_reflection__void, 0)
+	ZEND_ME(reflection_function, getAnnotations, arginfo_reflection__void, 0)
+	ZEND_ME(reflection_function, getAnnotation, arginfo_reflection_function_getAnnotation, 0)
+	ZEND_ME(reflection_function, hasAnnotation, arginfo_reflection_function_getAnnotation, 0)
 	ZEND_ME(reflection_function, getEndLine, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_function, getExtension, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_function, getExtensionName, arginfo_reflection__void, 0)
@@ -5796,6 +6419,15 @@
 	ZEND_ARG_INFO(0, interface)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_class_getAnnotations, 0, 0, 0)
+	ZEND_ARG_INFO(0, filter)
+ZEND_END_ARG_INFO()	
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_class_getAnnotation, 0, 0, 1)
+	ZEND_ARG_INFO(0, name)
+	ZEND_ARG_INFO(0, filter)
+ZEND_END_ARG_INFO()
+
 static const zend_function_entry reflection_class_functions[] = {
 	ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
 	ZEND_ME(reflection_class, export, arginfo_reflection_class_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC)
@@ -5810,6 +6442,9 @@
 	ZEND_ME(reflection_class, getStartLine, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_class, getEndLine, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_class, getDocComment, arginfo_reflection__void, 0)
+	ZEND_ME(reflection_class, getAnnotations, arginfo_reflection_class_getAnnotations, 0)
+	ZEND_ME(reflection_class, getAnnotation, arginfo_reflection_class_getAnnotation, 0)
+	ZEND_ME(reflection_class, hasAnnotation, arginfo_reflection_class_getAnnotation, 0)
 	ZEND_ME(reflection_class, getConstructor, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_class, hasMethod, arginfo_reflection_class_hasMethod, 0)
 	ZEND_ME(reflection_class, getMethod, arginfo_reflection_class_getMethod, 0)
@@ -5890,6 +6525,10 @@
 	ZEND_ARG_INFO(0, visible)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO(arginfo_reflection_property_getAnnotation, 0)
+	ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO()
+
 static const zend_function_entry reflection_property_functions[] = {
 	ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
 	ZEND_ME(reflection_property, export, arginfo_reflection_property_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC)
@@ -5906,6 +6545,9 @@
 	ZEND_ME(reflection_property, getModifiers, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_property, getDeclaringClass, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_property, getDocComment, arginfo_reflection__void, 0)
+	ZEND_ME(reflection_property, getAnnotations, arginfo_reflection__void, 0)
+	ZEND_ME(reflection_property, getAnnotation, arginfo_reflection_property_getAnnotation, 0)
+	ZEND_ME(reflection_property, hasAnnotation, arginfo_reflection_property_getAnnotation, 0)
 	ZEND_ME(reflection_property, setAccessible, arginfo_reflection_property_setAccessible, 0)
 	{NULL, NULL, NULL}
 };
@@ -5921,6 +6563,10 @@
 	ZEND_ARG_INFO(0, parameter)
 ZEND_END_ARG_INFO()
 
+ZEND_BEGIN_ARG_INFO(arginfo_reflection_parameter_getAnnotation, 0)
+    ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO()
+
 static const zend_function_entry reflection_parameter_functions[] = {
 	ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
 	ZEND_ME(reflection_parameter, export, arginfo_reflection_parameter_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC)
@@ -5945,6 +6591,9 @@
 	ZEND_ME(reflection_parameter, isOptional, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_parameter, isDefaultValueAvailable, arginfo_reflection__void, 0)
 	ZEND_ME(reflection_parameter, getDefaultValue, arginfo_reflection__void, 0)
+	ZEND_ME(reflection_parameter, getAnnotations, arginfo_reflection__void, 0)
+	ZEND_ME(reflection_parameter, getAnnotation, arginfo_reflection_parameter_getAnnotation, 0)
+	ZEND_ME(reflection_parameter, hasAnnotation, arginfo_reflection_parameter_getAnnotation, 0)
 	{NULL, NULL, NULL}
 };
 
@@ -5992,6 +6641,18 @@
 	ZEND_ME(reflection_zend_extension, getCopyright, arginfo_reflection__void, 0)
 	{NULL, NULL, NULL}
 };
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_annotation__construct, 0, 0, 1)
+	ZEND_ARG_INFO(0, reflector)
+	ZEND_ARG_ARRAY_INFO(0, data, 0)
+ZEND_END_ARG_INFO()
+
+static const zend_function_entry reflection_annotation_functions[] = {
+	ZEND_ME(reflection_annotation, __construct, arginfo_reflection_annotation__construct, ZEND_ACC_PUBLIC)
+	ZEND_ME(reflection_annotation, getValue, arginfo_reflection__void, 0)
+	{NULL, NULL, NULL}
+};
+
 /* }}} */
 
 const zend_function_entry reflection_ext_functions[] = { /* {{{ */
@@ -6018,6 +6679,50 @@
 }
 /* }}} */
 
+/* {{{ _reflection_annotation_read_property */
+static zval *_reflection_annotation_read_property(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
+{
+	zend_object_handlers * std_hnd;
+	zend_class_entry *ce;
+	zval *retval = EG(uninitialized_zval_ptr);
+
+	ce = Z_OBJCE_P(object);
+
+	if (Z_TYPE_P(member) == IS_STRING) {
+		if (zend_symtable_exists(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1)) {
+			std_hnd = zend_get_std_object_handlers();
+			retval = std_hnd->read_property(object, member, type, key TSRMLS_CC);
+		} else {
+			zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Unknown property '%s' on annotation '%s'", Z_STRVAL_P(member), ce->name);
+		}
+	} else {
+		zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Unknown property on annotation '%s'", ce->name);
+	}
+	return retval;
+}
+/* }}} */
+
+/* {{{ _reflection_annotation_write_property */
+static void _reflection_annotation_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
+{
+	zend_object_handlers *std_hnd;
+	zend_class_entry *ce;
+
+	ce = Z_OBJCE_P(object);
+
+	if (Z_TYPE_P(member) == IS_STRING) {
+		if (zend_symtable_exists(&ce->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member) + 1)) {
+			std_hnd = zend_get_std_object_handlers();
+			std_hnd->write_property(object, member, value, key TSRMLS_CC);
+		} else {
+			zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Unknown property '%s' on annotation '%s'", Z_STRVAL_P(member), ce->name);
+		}
+	} else {
+		zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Unknown property on annotation '%s'", ce->name);
+	}
+}
+/* }}} */
+
 PHP_MINIT_FUNCTION(reflection) /* {{{ */
 {
 	zend_class_entry _reflection_entry;
@@ -6106,6 +6811,24 @@
 	reflection_register_implement(reflection_zend_extension_ptr, reflector_ptr TSRMLS_CC);
 	zend_declare_property_string(reflection_zend_extension_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC);
 
+	
+	INIT_CLASS_ENTRY(_reflection_entry, "ReflectionAnnotation", reflection_annotation_functions);
+	reflection_annotation_ptr = zend_register_internal_class(&_reflection_entry TSRMLS_CC);
+	reflection_annotation_ptr->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
+	reflection_annotation_ptr->create_object = reflection_annotation_new;
+	zend_declare_property_null(reflection_annotation_ptr, "value", sizeof("value")-1, ZEND_ACC_PROTECTED TSRMLS_CC);
+
+	memcpy(&reflection_annotation_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+	reflection_annotation_handlers.write_property = _reflection_annotation_write_property;
+	reflection_annotation_handlers.read_property = _reflection_annotation_read_property;
+
+	REGISTER_REFLECTION_CLASS_CONST_LONG(annotation, "INHERITED", ANNOTATION_INHERITED);
+	REGISTER_REFLECTION_CLASS_CONST_LONG(annotation, "DECLARED", ANNOTATION_DECLARED);
+	REGISTER_REFLECTION_CLASS_CONST_LONG(annotation, "ALL", ANNOTATION_ALL);
+
+	INIT_CLASS_ENTRY(_reflection_entry, "Inherited", NULL);
+	reflection_annotation_inherited_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_annotation_ptr, NULL TSRMLS_CC);
+
 	return SUCCESS;
 } /* }}} */
 
Index: ext/reflection/php_reflection.h
===================================================================
--- ext/reflection/php_reflection.h	(revision 309164)
+++ ext/reflection/php_reflection.h	(working copy)
@@ -41,8 +41,15 @@
 extern PHPAPI zend_class_entry *reflection_property_ptr;
 extern PHPAPI zend_class_entry *reflection_extension_ptr;
 extern PHPAPI zend_class_entry *reflection_zend_extension_ptr;
+extern PHPAPI zend_class_entry *reflection_annotation_ptr;
 
 PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object TSRMLS_DC);
+
+void reflection_create_annotation(zval *res, zend_annotation *annotation, zval *reflector, zend_class_entry *ce TSRMLS_DC);
+void reflection_add_declared_annotations(zval *return_value, HashTable *annotations, zval *reflector TSRMLS_DC);
+void reflection_add_inherited_annotations(zval *res, HashTable *annotations, zval *reflector TSRMLS_DC);
+int reflection_get_inherited_annotation(HashTable *annotations, const char *name, const uint nameLength, zval *reflector, zval *res TSRMLS_DC);
+
 	
 END_EXTERN_C()
 
Index: Zend/zend.h
===================================================================
--- Zend/zend.h	(revision 309164)
+++ Zend/zend.h	(working copy)
@@ -421,6 +421,29 @@
 typedef struct _zend_serialize_data zend_serialize_data;
 typedef struct _zend_unserialize_data zend_unserialize_data;
 
+#define ZEND_ANNOTATION_ZVAL 1
+#define ZEND_ANNOTATION_ANNO 2
+#define ZEND_ANNOTATION_HASH 3
+
+struct _zend_annotation {
+	char *annotation_name;
+	unsigned int aname_len;
+
+	HashTable *values;
+	zval *instance;
+};
+typedef struct _zend_annotation zend_annotation;
+
+struct _zend_annotation_value {
+	zend_uchar type;
+	union _zend_annotation_value_value {
+		zend_annotation *annotation;
+		zval *zval;
+		HashTable *ht;	
+	} value;
+};
+typedef struct _zend_annotation_value zend_annotation_value;
+
 struct _zend_trait_method_reference {
 	char* method_name;
 	unsigned int mname_len;
@@ -516,12 +539,14 @@
 			zend_uint line_end;
 			char *doc_comment;
 			zend_uint doc_comment_len;
+			HashTable *annotations;
 		} user;
 		struct {
 			const struct _zend_function_entry *builtin_functions;
 			struct _zend_module_entry *module;
 		} internal;
 	} info;
+	
 };
 
 #include "zend_stream.h"
Index: Zend/zend_compile.c
===================================================================
--- Zend/zend_compile.c	(revision 309164)
+++ Zend/zend_compile.c	(working copy)
@@ -103,6 +103,7 @@
 	if (property_info->doc_comment) {
 		property_info->doc_comment = estrndup(property_info->doc_comment, property_info->doc_comment_len);
 	}
+	property_info->inherited = 1;
 }
 /* }}} */
 
@@ -122,6 +123,10 @@
 	if (property_info->doc_comment) {
 		efree(property_info->doc_comment);
 	}
+	if (!property_info->inherited && property_info->annotations) {
+		zend_hash_destroy(property_info->annotations);
+		efree(property_info->annotations);
+	}
 }
 /* }}} */
 
@@ -198,6 +203,9 @@
 	init_compiler_declarables(TSRMLS_C);
 	zend_stack_init(&CG(context_stack));
 
+	CG(annotations) = NULL;
+	zend_stack_init(&CG(annotation_stack));
+
 	CG(encoding_declared) = 0;
 }
 /* }}} */
@@ -236,6 +244,12 @@
 	zend_hash_destroy(&CG(filenames_table));
 	zend_llist_destroy(&CG(open_files));
 	zend_stack_destroy(&CG(context_stack));
+
+	zend_stack_destroy(&CG(annotation_stack));
+	if (CG(annotations)) {
+		zend_hash_destroy(CG(annotations));
+		efree(CG(annotations));
+	}
 }
 /* }}} */
 
@@ -1718,6 +1732,11 @@
 		CG(doc_comment) = NULL;
 		CG(doc_comment_len) = 0;
 	}
+
+	if (CG(annotations)) {
+		CG(active_op_array)->annotations = CG(annotations);
+		CG(annotations) = NULL;
+	}
 }
 /* }}} */
 
@@ -1844,6 +1863,13 @@
 	cur_arg_info->pass_by_reference = pass_by_reference;
 	cur_arg_info->class_name = NULL;
 	cur_arg_info->class_name_len = 0;
+	
+	if (CG(annotations)) {
+		cur_arg_info->annotations = CG(annotations);
+		CG(annotations) = NULL;
+	} else {
+		cur_arg_info->annotations = NULL;
+	}
 
 	if (class_type->op_type != IS_UNUSED) {
 		cur_arg_info->allow_null = 0;
@@ -3559,6 +3585,7 @@
 	}
 
 	fe->op_array.doc_comment = estrndup(fe->op_array.doc_comment, fe->op_array.doc_comment_len);
+
 	fe->op_array.try_catch_array = (zend_try_catch_element*)estrndup((char*)fe->op_array.try_catch_array, sizeof(zend_try_catch_element) * fe->op_array.last_try_catch);
 
 	fe->op_array.brk_cont_array = (zend_brk_cont_element*)estrndup((char*)fe->op_array.brk_cont_array, sizeof(zend_brk_cont_element) * fe->op_array.last_brk_cont);
@@ -3967,7 +3994,7 @@
 
 			zend_declare_property_ex(ce, prop_name, prop_name_length, 
 									 prop_value, property_info->flags, 
-								     property_info->doc_comment, property_info->doc_comment_len TSRMLS_CC);
+								     property_info->doc_comment, property_info->doc_comment_len, NULL TSRMLS_CC);
 		}
 	}
 }
@@ -4672,6 +4699,11 @@
 		CG(doc_comment) = NULL;
 		CG(doc_comment_len) = 0;
 	}
+
+	if (CG(annotations)) {
+		CG(active_class_entry)->info.user.annotations = CG(annotations);
+		CG(annotations) = NULL;
+	}
 }
 /* }}} */
 
@@ -4862,6 +4894,7 @@
 	zend_property_info *existing_property_info;
 	char *comment = NULL;
 	int comment_len = 0;
+	HashTable *annotations = NULL;
 
 	if (CG(active_class_entry)->ce_flags & ZEND_ACC_INTERFACE) {
 		zend_error(E_COMPILE_ERROR, "Interfaces may not include member variables");
@@ -4895,7 +4928,13 @@
 		CG(doc_comment_len) = 0;
 	}
 
-	zend_declare_property_ex(CG(active_class_entry), zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len + 1, 0 TSRMLS_CC), var_name->u.constant.value.str.len, property, access_type, comment, comment_len TSRMLS_CC);
+	if (CG(annotations)) {
+		annotations = CG(annotations);
+		CG(annotations) = NULL;
+	}
+
+
+	zend_declare_property_ex(CG(active_class_entry), zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len + 1, 0 TSRMLS_CC), var_name->u.constant.value.str.len, property, access_type, comment, comment_len, annotations TSRMLS_CC);
 	efree(var_name->u.constant.value.str.val);
 }
 /* }}} */
@@ -6327,6 +6366,7 @@
 		ce->static_members_table = ce->default_static_members_table;
 		ce->info.user.doc_comment = NULL;
 		ce->info.user.doc_comment_len = 0;
+		ce->info.user.annotations = NULL;
 	}
 
 	ce->default_properties_count = 0;
@@ -6729,6 +6769,213 @@
 }
 /* }}} */
 
+static void zend_annotation_dtor(void **ptr) { /* {{{ */
+	zend_annotation *a = (zend_annotation *) *ptr;
+	efree(a->annotation_name);
+	if (a->values) {
+		zend_hash_destroy(a->values);
+		efree(a->values);
+	}
+	if (a->instance) {
+		zval_ptr_dtor(&a->instance);
+	}
+	efree(*ptr);
+}
+/* }}} */
+
+static void zend_annotation_value_dtor(void **ptr) { /* {{{ */
+	zend_annotation_value *value = (zend_annotation_value *) *ptr;
+	value->type &= ~IS_CONSTANT_INDEX;
+	if (value->type == ZEND_ANNOTATION_ZVAL) {
+		zval_dtor(value->value.zval);
+		efree(value->value.zval);
+	} else if (value->type == ZEND_ANNOTATION_HASH) {
+		zend_hash_destroy(value->value.ht);
+		efree(value->value.ht);
+	} else if (value->type == ZEND_ANNOTATION_ANNO) {
+		zend_annotation **a = &value->value.annotation;
+		zend_annotation_dtor((void *) a);
+	}
+	efree(*ptr);
+}
+/* }}} */
+
+void zend_do_begin_annotation_declaration(const znode *annotation_token, znode *annotation_name, int params TSRMLS_DC) /* {{{ */
+{
+	zval *name;
+	zend_annotation *annotation_ptr;
+
+    if (annotation_name->op_type == IS_CONST &&
+        ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(annotation_name->u.constant), Z_STRLEN(annotation_name->u.constant))) {
+        ulong fetch_type = ZEND_FETCH_CLASS_GLOBAL;
+
+        zend_resolve_class_name(annotation_name, &fetch_type, 1 TSRMLS_CC);
+    } else {
+        zend_error(E_COMPILE_ERROR, "Bad class name in annotation statement");
+    }
+
+	name = &annotation_name->u.constant;
+
+	annotation_ptr = (zend_annotation *) emalloc(sizeof(zend_annotation));
+	annotation_ptr->annotation_name = Z_STRVAL_P(name);
+	annotation_ptr->aname_len = Z_STRLEN_P(name);
+
+	if (params) {
+		annotation_ptr->values = (HashTable *) emalloc(sizeof(HashTable));
+		zend_hash_init(annotation_ptr->values, 0, NULL, (dtor_func_t) zend_annotation_value_dtor, 0);
+	} else {
+		annotation_ptr->values = NULL;
+	}
+	annotation_ptr->instance = NULL;
+	
+	zend_stack_push(&CG(annotation_stack), (void *) &annotation_ptr, sizeof(zend_annotation *));
+}
+/* }}} */
+
+void zend_do_end_annotation_declaration(TSRMLS_D) /* {{{ */
+{
+	char *lc_name = NULL;
+	zend_annotation **annotation_ptr_ptr, *annotation_ptr;
+
+	zend_stack_top(&CG(annotation_stack), (void **) &annotation_ptr_ptr);
+	annotation_ptr = *annotation_ptr_ptr;
+	zend_stack_del_top(&CG(annotation_stack));
+
+	if (zend_stack_is_empty(&CG(annotation_stack))) {
+		if (!CG(annotations)) {
+			CG(annotations) = (HashTable *) emalloc(sizeof(HashTable));
+			zend_hash_init(CG(annotations), 0, NULL, (dtor_func_t) zend_annotation_dtor, 0);
+		}
+
+		lc_name = zend_str_tolower_dup(annotation_ptr->annotation_name, annotation_ptr->aname_len);
+
+		if (zend_hash_add(CG(annotations), lc_name, annotation_ptr->aname_len + 1, &annotation_ptr, sizeof(zend_annotation *), NULL) == FAILURE) {
+			efree(lc_name);
+			zend_error(E_ERROR, "Cannot redeclare annotation '%s'", annotation_ptr->annotation_name);
+		}
+		efree(lc_name);
+	}
+}
+/* }}} */
+
+void zend_do_add_annotation_value(znode *value_name TSRMLS_DC) /* {{{ */
+{
+	zend_annotation **annotation_ptr_ptr, *annotation_ptr;
+	zend_annotation_value **annotation_value_ptr_ptr, *annotation_value_ptr;
+
+	zend_stack_top(&CG(annotation_stack), (void **) &annotation_value_ptr_ptr);
+	annotation_value_ptr = *annotation_value_ptr_ptr;
+	zend_stack_del_top(&CG(annotation_stack));
+	zend_stack_top(&CG(annotation_stack), (void **) &annotation_ptr_ptr);
+	annotation_ptr = *annotation_ptr_ptr;
+
+	if (value_name) { 
+		if (zend_hash_add(annotation_ptr->values, Z_STRVAL(value_name->u.constant), Z_STRLEN(value_name->u.constant) + 1, &annotation_value_ptr, sizeof(zend_annotation_value *), NULL) == FAILURE) {
+			zend_error(E_ERROR, "Cannot redeclare property '%s' on annotation '%s'", Z_STRVAL(value_name->u.constant), annotation_ptr->annotation_name);			
+		}
+		zend_do_free(value_name TSRMLS_CC);
+	} else {
+		zend_hash_add(annotation_ptr->values, "value", sizeof("value"), &annotation_value_ptr, sizeof(zend_annotation_value *), NULL);
+	}
+}
+/* }}} */
+
+void zend_do_init_annotation_array(TSRMLS_D) /* {{{ */
+{
+	HashTable *ht = (HashTable *) emalloc(sizeof(HashTable));
+	zend_hash_init(ht, 0, NULL, (dtor_func_t) zend_annotation_value_dtor, 0);
+	zend_stack_push(&CG(annotation_stack), (void *) &ht, sizeof(HashTable *));
+}
+/* }}} */
+
+void zend_do_add_annotation_array_element(znode *offset TSRMLS_DC) /* {{{ */
+{
+	HashTable **ht_ptr_ptr, *ht_ptr;
+	zend_annotation_value **annotation_value_ptr_ptr, *annotation_value_ptr;
+
+	zend_stack_top(&CG(annotation_stack), (void **) &annotation_value_ptr_ptr);
+	annotation_value_ptr = *annotation_value_ptr_ptr;
+	zend_stack_del_top(&CG(annotation_stack));
+
+	zend_stack_top(&CG(annotation_stack), (void **) &ht_ptr_ptr);
+	ht_ptr = *ht_ptr_ptr;
+
+	if (offset) {
+        switch (offset->u.constant.type & IS_CONSTANT_TYPE_MASK) {
+            case IS_CONSTANT:
+                /* Ugly hack to denote that this value has a constant index */
+                annotation_value_ptr->type |= IS_CONSTANT_INDEX;
+                Z_STRVAL(offset->u.constant) = erealloc(Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+3);
+                Z_STRVAL(offset->u.constant)[Z_STRLEN(offset->u.constant)+1] = Z_TYPE(offset->u.constant);
+                Z_STRVAL(offset->u.constant)[Z_STRLEN(offset->u.constant)+2] = 0;
+                zend_symtable_update(ht_ptr, Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+3, &annotation_value_ptr, sizeof(zend_annotation_value *), NULL);
+                zval_dtor(&offset->u.constant);
+                break;
+            case IS_STRING:
+                zend_symtable_update(ht_ptr, Z_STRVAL(offset->u.constant), Z_STRLEN(offset->u.constant)+1, &annotation_value_ptr, sizeof(zend_annotation_value *), NULL);
+                zval_dtor(&offset->u.constant);
+                break;
+            case IS_NULL:
+                zend_symtable_update(ht_ptr, "", 1, &annotation_value_ptr, sizeof(zend_annotation_value *), NULL);
+                break;
+            case IS_LONG:
+            case IS_BOOL:
+                zend_hash_index_update(ht_ptr, Z_LVAL(offset->u.constant), &annotation_value_ptr, sizeof(zend_annotation_value *), NULL);
+                break;
+            case IS_DOUBLE:
+                zend_hash_index_update(ht_ptr, zend_dval_to_lval(Z_DVAL(offset->u.constant)), &annotation_value_ptr, sizeof(zend_annotation_value *), NULL);
+                break;
+            case IS_CONSTANT_ARRAY:
+                zend_error(E_ERROR, "Illegal offset type");
+                break;
+		}
+	} else {
+		zend_hash_next_index_insert(ht_ptr, &annotation_value_ptr, sizeof(zend_annotation_value *), NULL);
+	}
+}
+/* }}} */
+
+void zend_do_scalar_annotation_value(znode *value TSRMLS_DC) /* {{{ */
+{
+	zend_annotation_value *av;
+	if(Z_TYPE(value->u.constant) == IS_CONSTANT_ARRAY) {
+		zend_error(E_COMPILE_ERROR, "Arrays are not allowed in annotation properties");
+		return;
+	}
+	av = (zend_annotation_value *) emalloc(sizeof(zend_annotation_value));
+	av->type = ZEND_ANNOTATION_ZVAL;
+	ALLOC_ZVAL(av->value.zval);
+	INIT_PZVAL_COPY(av->value.zval, &value->u.constant);
+	zend_stack_push(&CG(annotation_stack), (void *) &av, sizeof(zend_annotation_value *));
+}
+/* }}} */
+
+void zend_do_array_annotation_value(TSRMLS_D) /* {{{ */
+{
+	HashTable **ht_ptr_ptr, *ht_ptr;
+	zend_annotation_value *av = (zend_annotation_value *) emalloc(sizeof(zend_annotation_value));
+	zend_stack_top(&CG(annotation_stack), (void **) &ht_ptr_ptr);
+	ht_ptr = *ht_ptr_ptr;
+	zend_stack_del_top(&CG(annotation_stack));
+	av->type = ZEND_ANNOTATION_HASH;
+	av->value.ht = ht_ptr;
+	zend_stack_push(&CG(annotation_stack), (void *) &av, sizeof(zend_annotation_value *));
+}
+/* }}} */
+
+void zend_do_annotation_annotation_value(TSRMLS_D) /* {{{ */
+{
+	zend_annotation **annotation_ptr_ptr, *annotation_ptr;
+	zend_annotation_value *av = (zend_annotation_value *) emalloc(sizeof(zend_annotation_value));
+	zend_stack_top(&CG(annotation_stack), (void **) &annotation_ptr_ptr);
+	annotation_ptr = *annotation_ptr_ptr;
+	zend_stack_del_top(&CG(annotation_stack));
+	av->type = ZEND_ANNOTATION_ANNO;
+	av->value.annotation = annotation_ptr;
+	zend_stack_push(&CG(annotation_stack), (void *) &av, sizeof(zend_annotation_value *));
+}
+/* }}} */
+
 /*
  * Local variables:
  * tab-width: 4
Index: Zend/zend_compile.h
===================================================================
--- Zend/zend_compile.h	(revision 309164)
+++ Zend/zend_compile.h	(working copy)
@@ -210,6 +210,8 @@
 	char *doc_comment;
 	int doc_comment_len;
 	zend_class_entry *ce;
+	HashTable *annotations;
+	zend_bool inherited;
 } zend_property_info;
 
 
@@ -221,6 +223,7 @@
 	zend_uchar type_hint;
 	zend_bool allow_null;
 	zend_bool pass_by_reference;
+	HashTable *annotations;
 } zend_arg_info;
 
 /* the following structure repeats the layout of zend_arg_info,
@@ -283,6 +286,8 @@
 	zend_uint doc_comment_len;
 	zend_uint early_binding; /* the linked list of delayed declarations */
 
+	HashTable *annotations;
+
 	zend_literal *literals;
 	int last_literal;
 
@@ -616,6 +621,15 @@
 void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC);
 void zend_release_labels(TSRMLS_D);
 
+void zend_do_begin_annotation_declaration(const znode *annotation_token, znode *annotation_name, int param TSRMLS_DC);
+void zend_do_end_annotation_declaration(TSRMLS_D);
+void zend_do_add_annotation_value(znode *name TSRMLS_DC);
+void zend_do_init_annotation_array(TSRMLS_D);
+void zend_do_add_annotation_array_element(znode *offset TSRMLS_DC);
+void zend_do_scalar_annotation_value(znode *value TSRMLS_DC);
+void zend_do_array_annotation_value(TSRMLS_D);
+void zend_do_annotation_annotation_value(TSRMLS_D);
+
 ZEND_API void function_add_ref(zend_function *function);
 
 #define INITIAL_OP_ARRAY_SIZE 64
Index: Zend/zend_API.c
===================================================================
--- Zend/zend_API.c	(revision 309164)
+++ Zend/zend_API.c	(working copy)
@@ -3250,7 +3250,7 @@
 }
 /* }}} */
 
-ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC) /* {{{ */
+ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len, HashTable *annotations TSRMLS_DC) /* {{{ */
 {
 	zend_property_info property_info, *property_info_ptr;
 	char *interned_name;
@@ -3342,7 +3342,10 @@
 	property_info.doc_comment = doc_comment;
 	property_info.doc_comment_len = doc_comment_len;
 
+	property_info.annotations = annotations;
+
 	property_info.ce = ce;
+	property_info.inherited = 0;
 
 	zend_hash_quick_update(&ce->properties_info, name, name_length + 1, h, &property_info, sizeof(zend_property_info), NULL);
 
@@ -3352,7 +3355,7 @@
 
 ZEND_API int zend_declare_property(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type TSRMLS_DC) /* {{{ */
 {
-	return zend_declare_property_ex(ce, name, name_length, property, access_type, NULL, 0 TSRMLS_CC);
+	return zend_declare_property_ex(ce, name, name_length, property, access_type, NULL, 0, NULL TSRMLS_CC);
 }
 /* }}} */
 
Index: Zend/zend_API.h
===================================================================
--- Zend/zend_API.h	(revision 309164)
+++ Zend/zend_API.h	(working copy)
@@ -294,7 +294,7 @@
 ZEND_API const char *zend_get_module_version(const char *module_name);
 ZEND_API int zend_get_module_started(const char *module_name);
 ZEND_API int zend_declare_property(zend_class_entry *ce, char *name, int name_length, zval *property, int access_type TSRMLS_DC);
-ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len TSRMLS_DC);
+ZEND_API int zend_declare_property_ex(zend_class_entry *ce, const char *name, int name_length, zval *property, int access_type, char *doc_comment, int doc_comment_len, HashTable *annotations TSRMLS_DC);
 ZEND_API int zend_declare_property_null(zend_class_entry *ce, char *name, int name_length, int access_type TSRMLS_DC);
 ZEND_API int zend_declare_property_bool(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC);
 ZEND_API int zend_declare_property_long(zend_class_entry *ce, char *name, int name_length, long value, int access_type TSRMLS_DC);
Index: Zend/zend_language_parser.y
===================================================================
--- Zend/zend_language_parser.y	(revision 309164)
+++ Zend/zend_language_parser.y	(working copy)
@@ -47,7 +47,7 @@
 %}
 
 %pure_parser
-%expect 2
+%expect 2 
 
 %left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
 %left ','
@@ -318,21 +318,23 @@
 unticked_function_declaration_statement:
 		function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); }
 			'(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
+	|	non_empty_annotations function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 0, $1.op_type, NULL TSRMLS_CC); }
+			'(' parameter_list ')' '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); }
 ;
 
 unticked_class_declaration_statement:
-		class_entry_type T_STRING extends_from
-			{ zend_do_begin_class_declaration(&$1, &$2, &$3 TSRMLS_CC); }
+		annotations class_entry_type T_STRING extends_from
+			{ zend_do_begin_class_declaration(&$2, &$3, &$4 TSRMLS_CC); }
 			implements_list
 			'{'
 				class_statement_list
-			'}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
-	|	interface_entry T_STRING
-			{ zend_do_begin_class_declaration(&$1, &$2, NULL TSRMLS_CC); }
+			'}' { zend_do_end_class_declaration(&$2, &$3 TSRMLS_CC); }
+	|	annotations interface_entry T_STRING
+			{ zend_do_begin_class_declaration(&$2, &$3, NULL TSRMLS_CC); }
 			interface_extends_list
 			'{'
 				class_statement_list
-			'}' { zend_do_end_class_declaration(&$1, &$2 TSRMLS_CC); }
+			'}' { zend_do_end_class_declaration(&$2, &$3 TSRMLS_CC); }
 ;
 
 
@@ -461,14 +463,14 @@
 
 
 non_empty_parameter_list:
-		optional_class_type T_VARIABLE				{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$2, &$$, NULL, &$1, 0 TSRMLS_CC); }
-	|	optional_class_type '&' T_VARIABLE			{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$3, &$$, NULL, &$1, 1 TSRMLS_CC); }
-	|	optional_class_type '&' T_VARIABLE '=' static_scalar			{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$3, &$$, &$5, &$1, 1 TSRMLS_CC); }
-	|	optional_class_type T_VARIABLE '=' static_scalar				{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$2, &$$, &$4, &$1, 0 TSRMLS_CC); }
-	|	non_empty_parameter_list ',' optional_class_type T_VARIABLE 	{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$4, &$$, NULL, &$3, 0 TSRMLS_CC); }
-	|	non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE	{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$5, &$$, NULL, &$3, 1 TSRMLS_CC); }
-	|	non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE	 '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$5, &$$, &$7, &$3, 1 TSRMLS_CC); }
-	|	non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar 	{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$4, &$$, &$6, &$3, 0 TSRMLS_CC); }
+		annotations optional_class_type T_VARIABLE				{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$3, &$$, NULL, &$2, 0 TSRMLS_CC); }
+	|	annotations optional_class_type '&' T_VARIABLE			{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$4, &$$, NULL, &$2, 1 TSRMLS_CC); }
+	|	annotations optional_class_type '&' T_VARIABLE '=' static_scalar			{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$4, &$$, &$6, &$2, 1 TSRMLS_CC); }
+	|	annotations optional_class_type T_VARIABLE '=' static_scalar				{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$3, &$$, &$5, &$2, 0 TSRMLS_CC); }
+	|	non_empty_parameter_list ',' annotations optional_class_type T_VARIABLE 	{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$5, &$$, NULL, &$4, 0 TSRMLS_CC); }
+	|	non_empty_parameter_list ',' annotations optional_class_type '&' T_VARIABLE	{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$6, &$$, NULL, &$4, 1 TSRMLS_CC); }
+	|	non_empty_parameter_list ',' annotations optional_class_type '&' T_VARIABLE	 '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$6, &$$, &$8, &$4, 1 TSRMLS_CC); }
+	|	non_empty_parameter_list ',' annotations optional_class_type T_VARIABLE '=' static_scalar 	{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$5, &$$, &$7, &$4, 0 TSRMLS_CC); }
 ;
 
 
@@ -531,11 +533,11 @@
 
 
 class_statement:
-		variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';'
+		annotations variable_modifiers { CG(access_type) = Z_LVAL($2.u.constant); } class_variable_declaration ';'
 	|	class_constant_declaration ';'
 	|	trait_use_statement
-	|	method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); } '('
-			parameter_list ')' method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
+	|	annotations method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$3, &$5, 1, $4.op_type, &$2 TSRMLS_CC); } '('
+			parameter_list ')' method_body { zend_do_abstract_method(&$5, &$2, &$10 TSRMLS_CC); zend_do_end_function_declaration(&$3 TSRMLS_CC); }
 ;
 
 trait_use_statement:
@@ -1095,6 +1097,66 @@
 	|	variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
 ;
 
+
+annotations:
+		non_empty_annotations 
+	|	/* empty */
+;
+
+non_empty_annotations:
+		non_empty_annotations annotation { zend_do_end_annotation_declaration(TSRMLS_C); }
+	|	annotation { zend_do_end_annotation_declaration(TSRMLS_C); }
+;
+
+annotation:
+		'[' class_name { zend_do_begin_annotation_declaration(&$1, &$2, 1 TSRMLS_CC); } '(' annotation_values ')' ']'
+	|	'[' class_name { zend_do_begin_annotation_declaration(&$1, &$2, 0 TSRMLS_CC); } ']'
+;
+
+annotation_values:
+		annotation_plain_value { zend_do_add_annotation_value(NULL TSRMLS_CC); } ',' annotation_value_list
+	|	annotation_plain_value { zend_do_add_annotation_value(NULL TSRMLS_CC); } 
+	|	annotation_value_list
+	|   /* empty */
+;
+
+annotation_value_list:
+		annotation_value_list ',' annotation_value
+	|   annotation_value
+;
+
+annotation_value:
+		T_STRING '=' annotation_plain_value { zend_do_add_annotation_value(&$1 TSRMLS_CC); }
+;
+
+annotation_plain_value:
+		annotation_scalar { zend_do_scalar_annotation_value(&$1 TSRMLS_CC); }
+	| 	annotation { zend_do_annotation_annotation_value(TSRMLS_C); }
+	|   annotation_array { zend_do_array_annotation_value(TSRMLS_C); }
+;
+
+annotation_scalar:
+		common_scalar       { $$ = $1; }
+	|	namespace_name      { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); }
+	|	T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant);  zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); }
+	|	T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); }
+	|	'+' static_scalar { ZVAL_LONG(&$1.u.constant, 0); add_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; }
+	|	'-' static_scalar { ZVAL_LONG(&$1.u.constant, 0); sub_function(&$2.u.constant, &$1.u.constant, &$2.u.constant TSRMLS_CC); $$ = $2; }
+	|	static_class_constant { $$ = $1; }
+;
+
+annotation_array:
+		T_ARRAY '(' { zend_do_init_annotation_array(TSRMLS_C); } annotation_array_list ')'
+	| 	T_ARRAY '(' ')' { zend_do_init_annotation_array(TSRMLS_C); }
+;
+
+annotation_array_list:
+		annotation_array_list ',' annotation_scalar T_DOUBLE_ARROW annotation_plain_value { zend_do_add_annotation_array_element(&$3 TSRMLS_CC); }
+	|	annotation_array_list ',' annotation_plain_value { zend_do_add_annotation_array_element(NULL TSRMLS_CC); }
+	| 	annotation_scalar T_DOUBLE_ARROW annotation_plain_value { zend_do_add_annotation_array_element(&$1 TSRMLS_CC); }
+	| 	annotation_plain_value { zend_do_add_annotation_array_element(NULL TSRMLS_CC); }
+;
+
 %%
 
 /*
Index: Zend/zend_globals.h
===================================================================
--- Zend/zend_globals.h	(revision 309164)
+++ Zend/zend_globals.h	(working copy)
@@ -129,6 +129,9 @@
 	char *doc_comment;
 	zend_uint doc_comment_len;
 
+	HashTable *annotations;
+	zend_stack annotation_stack;
+
 	zend_uint compiler_options; /* set of ZEND_COMPILE_* constants */
 
 	zval      *current_namespace;
Index: Zend/zend_opcode.c
===================================================================
--- Zend/zend_opcode.c	(revision 309164)
+++ Zend/zend_opcode.c	(working copy)
@@ -75,6 +75,8 @@
 	op_array->doc_comment = NULL;
 	op_array->doc_comment_len = 0;
 
+	op_array->annotations = NULL;
+
 	op_array->arg_info = NULL;
 	op_array->num_args = 0;
 	op_array->required_num_args = 0;
@@ -234,6 +236,10 @@
 			if (ce->trait_aliases[i]->alias) {
 				efree(ce->trait_aliases[i]->alias);
 			}
+			if (ce->info.user.annotations) {
+				zend_hash_destroy(ce->info.user.annotations);
+				efree(ce->info.user.annotations);
+			}
 			
 			efree(ce->trait_aliases[i]);
 			i++;
@@ -268,6 +274,7 @@
 	if (--ce->refcount > 0) {
 		return;
 	}
+	
 	switch (ce->type) {
 		case ZEND_USER_CLASS:
 			if (ce->default_properties_table) {
@@ -303,6 +310,11 @@
 				efree(ce->info.user.doc_comment);
 			}
 			
+			if (ce->info.user.annotations) {
+				zend_hash_destroy(ce->info.user.annotations);
+				efree(ce->info.user.annotations);
+			}
+
 			_destroy_zend_class_traits_info(ce);
 			
 			efree(ce);
@@ -391,6 +403,10 @@
 	if (op_array->doc_comment) {
 		efree(op_array->doc_comment);
 	}
+	if (op_array->annotations) {
+		zend_hash_destroy(op_array->annotations);
+		efree(op_array->annotations);
+	}
 	if (op_array->brk_cont_array) {
 		efree(op_array->brk_cont_array);
 	}
@@ -406,6 +422,11 @@
 			if (op_array->arg_info[i].class_name && !IS_INTERNED(op_array->arg_info[i].class_name)) {
 				efree((char*)op_array->arg_info[i].class_name);
 			}
+			if (op_array->arg_info[i].annotations) {
+				zend_hash_destroy(op_array->arg_info[i].annotations);
+				efree(op_array->arg_info[i].annotations);
+
+			}
 		}
 		efree(op_array->arg_info);
 	}
Index: tests/annotations/parser_001.phpt
===================================================================
--- tests/annotations/parser_001.phpt	(revision 0)
+++ tests/annotations/parser_001.phpt	(revision 0)
@@ -0,0 +1,17 @@
+--TEST--
+Annotation in class without value test
+--FILE--
+
+<?php
+
+[Annotation]
+class Foo {
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/ReflectionClass_getAnnotations_001.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotations_001.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotations_001.phpt	(revision 0)
@@ -0,0 +1,26 @@
+--TEST--
+ReflectionClass::getAnnotations with simple annotation
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+[SimpleAnnotation]
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation"]=>
+  object(SimpleAnnotation)#%d (1) {
+    ["value":protected]=>
+    NULL
+  }
+}
Index: tests/annotations/parser_011.phpt
===================================================================
--- tests/annotations/parser_011.phpt	(revision 0)
+++ tests/annotations/parser_011.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+Annotation in property using properties test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(name="value", foo="bar")]
+    public $bar;
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_021.phpt
===================================================================
--- tests/annotations/parser_021.phpt	(revision 0)
+++ tests/annotations/parser_021.phpt	(revision 0)
@@ -0,0 +1,34 @@
+--TEST--
+Complex Annotations in class test
+--FILE--
+
+<?php
+
+[Entity(tableName="users")]
+class User
+{
+    [Column(type="integer")]
+    [Id]
+    [GeneratedValue(strategy="AUTO")]
+    protected $id;
+
+    [ManyToMany(targetEntity="Phonenumber")]
+    [JoinTable(
+        name="users_phonenumbers",
+        joinColumns=array(
+            [JoinColumn(name="user_id", referencedColumnName="id")]
+		),
+        inverseJoinColumns=array(
+            [JoinColumn(name="phonenumber_id", referencedColumnName="id", unique=true)]
+		)
+    )]
+    function foo() {}
+}
+
+$user = new User();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_003.phpt
===================================================================
--- tests/annotations/parser_003.phpt	(revision 0)
+++ tests/annotations/parser_003.phpt	(revision 0)
@@ -0,0 +1,17 @@
+--TEST--
+Annotation in class using single property test
+--FILE--
+
+<?php
+
+[Annotation(name="value")]
+class Foo {
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/ReflectionClass_getAnnotations_003.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotations_003.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotations_003.phpt	(revision 0)
@@ -0,0 +1,55 @@
+--TEST--
+ReflectionClass::getAnnotations with complex annotations
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation1 extends ReflectionAnnotation {
+}
+class SimpleAnnotation2 extends ReflectionAnnotation {
+	public $foo;	
+}
+
+[SimpleAnnotation1(value=array(
+	[SimpleAnnotation2()],
+	[SimpleAnnotation2("test")],
+	[SimpleAnnotation2(foo="bar")]
+))]
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation1"]=>
+  object(SimpleAnnotation1)#%d (1) {
+    ["value":protected]=>
+    array(3) {
+      [0]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        NULL
+      }
+      [1]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        string(4) "test"
+      }
+      [2]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        string(3) "bar"
+        ["value":protected]=>
+        NULL
+      }
+    }
+  }
+}
Index: tests/annotations/parser_013.phpt
===================================================================
--- tests/annotations/parser_013.phpt	(revision 0)
+++ tests/annotations/parser_013.phpt	(revision 0)
@@ -0,0 +1,19 @@
+--TEST--
+Multiple Annotations in property test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(array("foo", "bar", "red"))]
+    [AnotherAnnotation]
+    public $bar;
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_005.phpt
===================================================================
--- tests/annotations/parser_005.phpt	(revision 0)
+++ tests/annotations/parser_005.phpt	(revision 0)
@@ -0,0 +1,17 @@
+--TEST--
+Annotation in class using array test
+--FILE--
+
+<?php
+
+[Annotation(array("foo", "bar", "red"))]
+class Foo {
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_023.phpt
===================================================================
--- tests/annotations/parser_023.phpt	(revision 0)
+++ tests/annotations/parser_023.phpt	(revision 0)
@@ -0,0 +1,15 @@
+--TEST--
+Annotation in function using unique value test
+--FILE--
+
+<?php
+
+[Annotation("value")]
+function foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_015.phpt
===================================================================
--- tests/annotations/parser_015.phpt	(revision 0)
+++ tests/annotations/parser_015.phpt	(revision 0)
@@ -0,0 +1,20 @@
+--TEST--
+Annotation in method without value test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation]
+    public function bar() {
+        echo 'do nothing';
+    }
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/ReflectionClass_getAnnotations_005.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotations_005.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotations_005.phpt	(revision 0)
@@ -0,0 +1,17 @@
+--TEST--
+ReflectionClass::getAnnotations with missing class 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+[SimpleAnnotation]
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+Fatal error: Class 'SimpleAnnotation' not found in %s line %d
Index: tests/annotations/parser_007.phpt
===================================================================
--- tests/annotations/parser_007.phpt	(revision 0)
+++ tests/annotations/parser_007.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+Annotation in property test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation]
+    public $bar;
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_025.phpt
===================================================================
--- tests/annotations/parser_025.phpt	(revision 0)
+++ tests/annotations/parser_025.phpt	(revision 0)
@@ -0,0 +1,15 @@
+--TEST--
+Annotation in function using properties test
+--FILE--
+
+<?php
+
+[Annotation(name="value", foo="bar")]
+function foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_017.phpt
===================================================================
--- tests/annotations/parser_017.phpt	(revision 0)
+++ tests/annotations/parser_017.phpt	(revision 0)
@@ -0,0 +1,20 @@
+--TEST--
+Annotation in method using single property test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(name="value")]
+    public function bar() {
+        echo 'do nothing';
+    }
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/ReflectionClass_getAnnotations_007.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotations_007.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotations_007.phpt	(revision 0)
@@ -0,0 +1,26 @@
+--TEST--
+ReflectionClass::getAnnotations with constant value 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {}
+
+[SimpleAnnotation(Foo::OK)]
+class Foo {
+	const OK = "OK!";
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation"]=>
+  object(SimpleAnnotation)#%d (1) {
+    ["value":protected]=>
+    string(3) "OK!"
+  }
+}
Index: tests/annotations/parser_009.phpt
===================================================================
--- tests/annotations/parser_009.phpt	(revision 0)
+++ tests/annotations/parser_009.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+Annotation in property using unique value test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation("value")]
+    public $bar;
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_027.phpt
===================================================================
--- tests/annotations/parser_027.phpt	(revision 0)
+++ tests/annotations/parser_027.phpt	(revision 0)
@@ -0,0 +1,16 @@
+--TEST--
+Multiple Annotations in function test
+--FILE--
+
+<?php
+
+[Annotation(array("foo", "bar", "red"))]
+[AnotherAnnotation]
+function foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_019.phpt
===================================================================
--- tests/annotations/parser_019.phpt	(revision 0)
+++ tests/annotations/parser_019.phpt	(revision 0)
@@ -0,0 +1,20 @@
+--TEST--
+Annotation in method using array test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(array("foo", "bar", "red"))]
+    public function bar() {
+        echo 'do nothing';
+    }
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_029.phpt
===================================================================
--- tests/annotations/parser_029.phpt	(revision 0)
+++ tests/annotations/parser_029.phpt	(revision 0)
@@ -0,0 +1,15 @@
+--TEST--
+Duplicated annotation value
+--FILE--
+
+<?php
+
+[Annotation(name="value", name="bar")]
+class foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECTF--
+Fatal error: Cannot redeclare property 'name' on annotation 'Annotation' in %s on line %d
Index: tests/annotations/ReflectionClass_hasAnnotation_001.phpt
===================================================================
--- tests/annotations/ReflectionClass_hasAnnotation_001.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_hasAnnotation_001.phpt	(revision 0)
@@ -0,0 +1,20 @@
+--TEST--
+ReflectionClass::hasAnnotation with simple annotation
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+[SimpleAnnotation]
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->hasAnnotation('SimpleAnnotation'));
+
+?>
+--EXPECTF--
+bool(true)
Index: tests/annotations/ReflectionParameter_getAnnotations_001.phpt
===================================================================
--- tests/annotations/ReflectionParameter_getAnnotations_001.phpt	(revision 0)
+++ tests/annotations/ReflectionParameter_getAnnotations_001.phpt	(revision 0)
@@ -0,0 +1,28 @@
+--TEST--
+ReflectionParameter::getAnnotations with simple annotation
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+function foo([SimpleAnnotation] $bar)
+{
+}
+
+$r = new ReflectionFunction('foo');
+foreach ($r->getParameters() as $argument) {
+	var_dump($argument->getAnnotations());
+}
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation"]=>
+  object(SimpleAnnotation)#%d (1) {
+    ["value":protected]=>
+    NULL
+  }
+}
Index: tests/annotations/ReflectionClass_hasAnnotation_003.phpt
===================================================================
--- tests/annotations/ReflectionClass_hasAnnotation_003.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_hasAnnotation_003.phpt	(revision 0)
@@ -0,0 +1,32 @@
+--TEST--
+ReflectionClass::hasAnnotation with Inherit 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+[Inherited]
+class Annotation1 extends ReflectionAnnotation {}
+class Annotation2 extends ReflectionAnnotation {}
+
+[Annotation1("inherited")]
+abstract class TestBase {
+}
+[Annotation2("declared")]
+class Test extends TestBase {
+}
+
+$r = new ReflectionClass('Test');
+var_dump($r->hasAnnotation('Annotation1', ReflectionAnnotation::INHERITED));
+var_dump($r->hasAnnotation('Annotation1', ReflectionAnnotation::DECLARED));
+var_dump($r->hasAnnotation('Annotation1', ReflectionAnnotation::ALL));
+var_dump($r->hasAnnotation('Annotation2', ReflectionAnnotation::INHERITED));
+var_dump($r->hasAnnotation('Annotation2', ReflectionAnnotation::DECLARED));
+var_dump($r->hasAnnotation('Annotation2', ReflectionAnnotation::ALL));
+?>
+--EXPECTF--
+bool(true)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(true)
Index: tests/annotations/ReflectionMethod_getAnnotations_002.phpt
===================================================================
--- tests/annotations/ReflectionMethod_getAnnotations_002.phpt	(revision 0)
+++ tests/annotations/ReflectionMethod_getAnnotations_002.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+ReflectionMethod::getAnnotations with no annotation 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class Foo {
+	public function bar() {}
+}
+
+$r = new ReflectionMethod('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(0) {
+}
Index: tests/annotations/ReflectionClass_getAnnotation_001.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotation_001.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotation_001.phpt	(revision 0)
@@ -0,0 +1,23 @@
+--TEST--
+ReflectionClass::getAnnotation with simple annotation
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+[SimpleAnnotation]
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotation('SimpleAnnotation'));
+
+?>
+--EXPECTF--
+object(SimpleAnnotation)#2 (1) {
+  ["value":protected]=>
+  NULL
+}
Index: tests/annotations/ReflectionParameter_getAnnotations_003.phpt
===================================================================
--- tests/annotations/ReflectionParameter_getAnnotations_003.phpt	(revision 0)
+++ tests/annotations/ReflectionParameter_getAnnotations_003.phpt	(revision 0)
@@ -0,0 +1,56 @@
+--TEST--
+ReflectionMethod::getAnnotations with complex annotations
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation1 extends ReflectionAnnotation {
+}
+class SimpleAnnotation2 extends ReflectionAnnotation {
+	public $foo;	
+}
+
+function foo([SimpleAnnotation1(value=array(
+		[SimpleAnnotation2()],
+		[SimpleAnnotation2("test")],
+		[SimpleAnnotation2(foo="bar")]
+	))] $bar) 
+{
+}
+
+$r = new ReflectionFunction('foo');
+foreach ($r->getParameters() as $argument) {
+	    var_dump($argument->getAnnotations());
+} 
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation1"]=>
+  object(SimpleAnnotation1)#%d (1) {
+    ["value":protected]=>
+    array(3) {
+      [0]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        NULL
+      }
+      [1]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        string(4) "test"
+      }
+      [2]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        string(3) "bar"
+        ["value":protected]=>
+        NULL
+      }
+    }
+  }
+}
Index: tests/annotations/ReflectionClass_getAnnotation_003.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotation_003.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotation_003.phpt	(revision 0)
@@ -0,0 +1,52 @@
+--TEST--
+ReflectionClass::getAnnotation with complex annotations
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation1 extends ReflectionAnnotation {
+}
+class SimpleAnnotation2 extends ReflectionAnnotation {
+	public $foo;	
+}
+
+[SimpleAnnotation1(value=array(
+	[SimpleAnnotation2()],
+	[SimpleAnnotation2("test")],
+	[SimpleAnnotation2(foo="bar")]
+))]
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotation('SimpleAnnotation1'));
+
+?>
+--EXPECTF--
+object(SimpleAnnotation1)#%d (1) {
+  ["value":protected]=>
+  array(3) {
+    [0]=>
+    object(SimpleAnnotation2)#%d (2) {
+      ["foo"]=>
+      NULL
+      ["value":protected]=>
+      NULL
+    }
+    [1]=>
+    object(SimpleAnnotation2)#%d (2) {
+      ["foo"]=>
+      NULL
+      ["value":protected]=>
+      string(4) "test"
+    }
+    [2]=>
+    object(SimpleAnnotation2)#%d (2) {
+      ["foo"]=>
+      string(3) "bar"
+      ["value":protected]=>
+      NULL
+    }
+  }
+}
Index: tests/annotations/ReflectionProperty_getAnnotations_002.phpt
===================================================================
--- tests/annotations/ReflectionProperty_getAnnotations_002.phpt	(revision 0)
+++ tests/annotations/ReflectionProperty_getAnnotations_002.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+ReflectionProperty::getAnnotations with no annotation 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class Foo {
+	public $bar;
+}
+
+$r = new ReflectionProperty('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(0) {
+}
Index: tests/annotations/ReflectionFunction_getAnnotations_002.phpt
===================================================================
--- tests/annotations/ReflectionFunction_getAnnotations_002.phpt	(revision 0)
+++ tests/annotations/ReflectionFunction_getAnnotations_002.phpt	(revision 0)
@@ -0,0 +1,16 @@
+--TEST--
+ReflectionFunction::getAnnotations with no annotation 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+function foo() {}
+
+$r = new ReflectionFunction('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(0) {
+}
Index: tests/annotations/ReflectionProperty_getAnnotations_004.phpt
===================================================================
--- tests/annotations/ReflectionProperty_getAnnotations_004.phpt	(revision 0)
+++ tests/annotations/ReflectionProperty_getAnnotations_004.phpt	(revision 0)
@@ -0,0 +1,29 @@
+--TEST--
+ReflectionProperty::getAnnotations with inherited property 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+abstract class Base {
+	[SimpleAnnotation]
+	public $bar;
+}
+class Foo extends Base {
+}
+
+$r = new ReflectionProperty('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation"]=>
+  object(SimpleAnnotation)#%d (1) {
+    ["value":protected]=>
+    NULL
+  }
+}
Index: tests/annotations/parser_010.phpt
===================================================================
--- tests/annotations/parser_010.phpt	(revision 0)
+++ tests/annotations/parser_010.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+Annotation in property using single property test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(name="value")]
+    public $bar;
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_002.phpt
===================================================================
--- tests/annotations/parser_002.phpt	(revision 0)
+++ tests/annotations/parser_002.phpt	(revision 0)
@@ -0,0 +1,17 @@
+--TEST--
+Annotation in class using unique value test
+--FILE--
+
+<?php
+
+[Annotation("value")]
+class Foo {
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_020.phpt
===================================================================
--- tests/annotations/parser_020.phpt	(revision 0)
+++ tests/annotations/parser_020.phpt	(revision 0)
@@ -0,0 +1,21 @@
+--TEST--
+Multiple Annotations in method test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(array("foo", "bar", "red"))]
+    [AnotherAnnotation]
+    public function bar() {
+        echo 'do nothing';
+    }
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_012.phpt
===================================================================
--- tests/annotations/parser_012.phpt	(revision 0)
+++ tests/annotations/parser_012.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+Annotation in property using array test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(array("foo", "bar", "red"))]
+    public $bar;
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_030.phpt
===================================================================
--- tests/annotations/parser_030.phpt	(revision 0)
+++ tests/annotations/parser_030.phpt	(revision 0)
@@ -0,0 +1,21 @@
+--TEST--
+Annotations on parameters
+--FILE--
+
+<?php
+
+function foo([Annotation(name="value")] $bar)
+{
+}
+
+class foo {
+	public function foo([Annotations()] $bar)
+	{
+	}
+}
+
+echo 'OK!';
+
+?>
+--EXPECTF--
+OK!
Index: tests/annotations/ReflectionClass_getAnnotations_002.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotations_002.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotations_002.phpt	(revision 0)
@@ -0,0 +1,17 @@
+--TEST--
+ReflectionClass::getAnnotations with no annotation 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(0) {
+}
Index: tests/annotations/parser_004.phpt
===================================================================
--- tests/annotations/parser_004.phpt	(revision 0)
+++ tests/annotations/parser_004.phpt	(revision 0)
@@ -0,0 +1,17 @@
+--TEST--
+Annotation in class using properties test
+--FILE--
+
+<?php
+
+[Annotation(name="value", foo="bar")]
+class Foo {
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_022.phpt
===================================================================
--- tests/annotations/parser_022.phpt	(revision 0)
+++ tests/annotations/parser_022.phpt	(revision 0)
@@ -0,0 +1,15 @@
+--TEST--
+Annotation in function without value test
+--FILE--
+
+<?php
+
+[Annotation]
+function foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_014.phpt
===================================================================
--- tests/annotations/parser_014.phpt	(revision 0)
+++ tests/annotations/parser_014.phpt	(revision 0)
@@ -0,0 +1,20 @@
+--TEST--
+Annotation in method test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation]
+    public function bar() {
+        echo 'do nothing';
+    }
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/ReflectionClass_getAnnotations_004.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotations_004.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotations_004.phpt	(revision 0)
@@ -0,0 +1,49 @@
+--TEST--
+ReflectionClass::getAnnotations with Inherit 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+[inherited]
+class Annotation1 extends ReflectionAnnotation {}
+class Annotation2 extends ReflectionAnnotation {}
+
+[Annotation1("inherited")]
+abstract class TestBase {
+}
+[Annotation2("declared")]
+class Test extends TestBase {
+}
+
+$r = new ReflectionClass('Test');
+var_dump($r->getAnnotations(ReflectionAnnotation::INHERITED));
+var_dump($r->getAnnotations(ReflectionAnnotation::DECLARED));
+var_dump($r->getAnnotations(ReflectionAnnotation::ALL));
+?>
+--EXPECTF--
+array(1) {
+  ["Annotation1"]=>
+  object(Annotation1)#%d (1) {
+    ["value":protected]=>
+    string(9) "inherited"
+  }
+}
+array(1) {
+  ["Annotation2"]=>
+  object(Annotation2)#%d (1) {
+    ["value":protected]=>
+    string(8) "declared"
+  }
+}
+array(2) {
+  ["Annotation2"]=>
+  object(Annotation2)#%d (1) {
+    ["value":protected]=>
+    string(8) "declared"
+  }
+  ["Annotation1"]=>
+  object(Annotation1)#%d (1) {
+    ["value":protected]=>
+    string(9) "inherited"
+  }
+}
Index: tests/annotations/parser_024.phpt
===================================================================
--- tests/annotations/parser_024.phpt	(revision 0)
+++ tests/annotations/parser_024.phpt	(revision 0)
@@ -0,0 +1,15 @@
+--TEST--
+Annotation in function using single property test
+--FILE--
+
+<?php
+
+[Annotation(name="value")]
+function foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_006.phpt
===================================================================
--- tests/annotations/parser_006.phpt	(revision 0)
+++ tests/annotations/parser_006.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+Multiple Annotations in class test
+--FILE--
+
+<?php
+
+[Annotation(array("foo", "bar", "red"))]
+[AnotherAnnotation]
+class Foo {
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_016.phpt
===================================================================
--- tests/annotations/parser_016.phpt	(revision 0)
+++ tests/annotations/parser_016.phpt	(revision 0)
@@ -0,0 +1,20 @@
+--TEST--
+Annotation in method using unique value test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation("value")]
+    public function bar() {
+        echo 'do nothing';
+    }
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/ReflectionClass_getAnnotations_006.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotations_006.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotations_006.phpt	(revision 0)
@@ -0,0 +1,19 @@
+--TEST--
+ReflectionClass::getAnnotations with bad class 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation {}
+
+[SimpleAnnotation]
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+Fatal error: ReflectionClass::getAnnotations(): 'SimpleAnnotation' must extend 'ReflectionAnnotation' to act as an annotation in %s on line %d 
Index: tests/annotations/parser_008.phpt
===================================================================
--- tests/annotations/parser_008.phpt	(revision 0)
+++ tests/annotations/parser_008.phpt	(revision 0)
@@ -0,0 +1,18 @@
+--TEST--
+Annotation in property without value test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation]
+    public $bar;
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_026.phpt
===================================================================
--- tests/annotations/parser_026.phpt	(revision 0)
+++ tests/annotations/parser_026.phpt	(revision 0)
@@ -0,0 +1,15 @@
+--TEST--
+Annotation in function using array test
+--FILE--
+
+<?php
+
+[Annotation(array("foo", "bar", "red"))]
+function foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
Index: tests/annotations/parser_018.phpt
===================================================================
--- tests/annotations/parser_018.phpt	(revision 0)
+++ tests/annotations/parser_018.phpt	(revision 0)
@@ -0,0 +1,20 @@
+--TEST--
+Annotation in method using properties test
+--FILE--
+
+<?php
+
+class Foo {
+    [Annotation(name="value", foo="bar")]
+    public function bar() {
+        echo 'do nothing';
+    }
+}
+
+$foo = new Foo();
+
+echo 'OK!';
+
+?>
+--EXPECT--
+OK!
\ No newline at end of file
Index: tests/annotations/parser_028.phpt
===================================================================
--- tests/annotations/parser_028.phpt	(revision 0)
+++ tests/annotations/parser_028.phpt	(revision 0)
@@ -0,0 +1,16 @@
+--TEST--
+Duplicated annotation
+--FILE--
+
+<?php
+
+[Annotation(name="value", foo="bar")]
+[Annotation(name="value", foo="bar")]
+class foo() {
+}
+
+echo 'OK!';
+
+?>
+--EXPECTF--
+Fatal error: Cannot redeclare annotation 'Annotation' in %s on line %d
Index: tests/annotations/ReflectionClass_hasAnnotation_002.phpt
===================================================================
--- tests/annotations/ReflectionClass_hasAnnotation_002.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_hasAnnotation_002.phpt	(revision 0)
@@ -0,0 +1,16 @@
+--TEST--
+ReflectionClass::hasAnnotation with no annotation 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->hasAnnotation('SimpleAnnotation'));
+
+?>
+--EXPECTF--
+bool(false)
Index: tests/annotations/ReflectionMethod_getAnnotations_001.phpt
===================================================================
--- tests/annotations/ReflectionMethod_getAnnotations_001.phpt	(revision 0)
+++ tests/annotations/ReflectionMethod_getAnnotations_001.phpt	(revision 0)
@@ -0,0 +1,27 @@
+--TEST--
+ReflectionMethod::getAnnotations with simple annotation
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+class Foo {
+	[SimpleAnnotation]
+	public function bar() {}
+}
+
+$r = new ReflectionMethod('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation"]=>
+  object(SimpleAnnotation)#%d (1) {
+    ["value":protected]=>
+    NULL
+  }
+}
Index: tests/annotations/ReflectionParameter_getAnnotations_002.phpt
===================================================================
--- tests/annotations/ReflectionParameter_getAnnotations_002.phpt	(revision 0)
+++ tests/annotations/ReflectionParameter_getAnnotations_002.phpt	(revision 0)
@@ -0,0 +1,19 @@
+--TEST--
+ReflectionMethod::getAnnotations with no annotation 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+function foo($bar)
+{
+}
+
+$r = new ReflectionFunction('foo');
+foreach ($r->getParameters() as $argument) {
+	var_dump($argument->getAnnotations());
+}
+?>
+--EXPECTF--
+array(0) {
+}
Index: tests/annotations/ReflectionMethod_getAnnotations_003.phpt
===================================================================
--- tests/annotations/ReflectionMethod_getAnnotations_003.phpt	(revision 0)
+++ tests/annotations/ReflectionMethod_getAnnotations_003.phpt	(revision 0)
@@ -0,0 +1,58 @@
+--TEST--
+ReflectionMethod::getAnnotations with complex annotations
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation1 extends ReflectionAnnotation {
+}
+class SimpleAnnotation2 extends ReflectionAnnotation {
+	public $foo;	
+}
+
+class Foo {
+	[SimpleAnnotation1(value=array(
+		[SimpleAnnotation2()],
+		[SimpleAnnotation2("test")],
+		[SimpleAnnotation2(foo="bar")]
+	))]
+	public function bar() {}
+}
+
+$foo = new Foo();
+
+$r = new ReflectionMethod('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation1"]=>
+  object(SimpleAnnotation1)#%d (1) {
+    ["value":protected]=>
+    array(3) {
+      [0]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        NULL
+      }
+      [1]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        string(4) "test"
+      }
+      [2]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        string(3) "bar"
+        ["value":protected]=>
+        NULL
+      }
+    }
+  }
+}
Index: tests/annotations/ReflectionClass_getAnnotation_002.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotation_002.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotation_002.phpt	(revision 0)
@@ -0,0 +1,16 @@
+--TEST--
+ReflectionClass::getAnnotation with no annotation 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class Foo {
+}
+
+$r = new ReflectionClass('Foo');
+var_dump($r->getAnnotation('SimpleAnnotation'));
+
+?>
+--EXPECTF--
+NULL
Index: tests/annotations/ReflectionProperty_getAnnotations_001.phpt
===================================================================
--- tests/annotations/ReflectionProperty_getAnnotations_001.phpt	(revision 0)
+++ tests/annotations/ReflectionProperty_getAnnotations_001.phpt	(revision 0)
@@ -0,0 +1,27 @@
+--TEST--
+ReflectionProperty::getAnnotations with simple annotation
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+class Foo {
+	[SimpleAnnotation]
+	public $bar;
+}
+
+$r = new ReflectionProperty('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation"]=>
+  object(SimpleAnnotation)#%d (1) {
+    ["value":protected]=>
+    NULL
+  }
+}
Index: tests/annotations/ReflectionFunction_getAnnotations_001.phpt
===================================================================
--- tests/annotations/ReflectionFunction_getAnnotations_001.phpt	(revision 0)
+++ tests/annotations/ReflectionFunction_getAnnotations_001.phpt	(revision 0)
@@ -0,0 +1,25 @@
+--TEST--
+ReflectionFunction::getAnnotations with simple annotation
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+[SimpleAnnotation]
+function foo() {}
+
+$r = new ReflectionFunction('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation"]=>
+  object(SimpleAnnotation)#%d (1) {
+    ["value":protected]=>
+    NULL
+  }
+}
Index: tests/annotations/ReflectionClass_getAnnotation_004.phpt
===================================================================
--- tests/annotations/ReflectionClass_getAnnotation_004.phpt	(revision 0)
+++ tests/annotations/ReflectionClass_getAnnotation_004.phpt	(revision 0)
@@ -0,0 +1,44 @@
+--TEST--
+ReflectionClass::getAnnotation with Inherit 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+[Inherited]
+class Annotation1 extends ReflectionAnnotation {}
+class Annotation2 extends ReflectionAnnotation {}
+
+[Annotation1("inherited")]
+abstract class TestBase {
+}
+[Annotation2("declared")]
+class Test extends TestBase {
+}
+
+$r = new ReflectionClass('Test');
+var_dump($r->getAnnotation('Annotation1', ReflectionAnnotation::INHERITED));
+var_dump($r->getAnnotation('Annotation1', ReflectionAnnotation::DECLARED));
+var_dump($r->getAnnotation('Annotation1', ReflectionAnnotation::ALL));
+var_dump($r->getAnnotation('Annotation2', ReflectionAnnotation::INHERITED));
+var_dump($r->getAnnotation('Annotation2', ReflectionAnnotation::DECLARED));
+var_dump($r->getAnnotation('Annotation2', ReflectionAnnotation::ALL));
+?>
+--EXPECTF--
+object(Annotation1)#%d (1) {
+  ["value":protected]=>
+  string(9) "inherited"
+}
+NULL
+object(Annotation1)#%d (1) {
+  ["value":protected]=>
+  string(9) "inherited"
+}
+NULL
+object(Annotation2)#%d (1) {
+  ["value":protected]=>
+  string(8) "declared"
+}
+object(Annotation2)#%d (1) {
+  ["value":protected]=>
+  string(8) "declared"
+}
Index: tests/annotations/ReflectionProperty_getAnnotations_003.phpt
===================================================================
--- tests/annotations/ReflectionProperty_getAnnotations_003.phpt	(revision 0)
+++ tests/annotations/ReflectionProperty_getAnnotations_003.phpt	(revision 0)
@@ -0,0 +1,56 @@
+--TEST--
+ReflectionProperty::getAnnotations with complex annotations
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation1 extends ReflectionAnnotation {
+}
+class SimpleAnnotation2 extends ReflectionAnnotation {
+	public $foo;	
+}
+
+class Foo {
+	[SimpleAnnotation1(value=array(
+		[SimpleAnnotation2()],
+		[SimpleAnnotation2("test")],
+		[SimpleAnnotation2(foo="bar")]
+	))]
+	public $bar;
+}
+
+$r = new ReflectionProperty('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation1"]=>
+  object(SimpleAnnotation1)#%d (1) {
+    ["value":protected]=>
+    array(3) {
+      [0]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        NULL
+      }
+      [1]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        string(4) "test"
+      }
+      [2]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        string(3) "bar"
+        ["value":protected]=>
+        NULL
+      }
+    }
+  }
+}
Index: tests/annotations/ReflectionFunction_getAnnotations_003.phpt
===================================================================
--- tests/annotations/ReflectionFunction_getAnnotations_003.phpt	(revision 0)
+++ tests/annotations/ReflectionFunction_getAnnotations_003.phpt	(revision 0)
@@ -0,0 +1,54 @@
+--TEST--
+ReflectionFunction::getAnnotations with complex annotations
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation1 extends ReflectionAnnotation {
+}
+class SimpleAnnotation2 extends ReflectionAnnotation {
+	public $foo;	
+}
+
+[SimpleAnnotation1(value=array(
+	[SimpleAnnotation2()],
+	[SimpleAnnotation2("test")],
+	[SimpleAnnotation2(foo="bar")]
+))]
+function foo() {}
+
+$r = new ReflectionFunction('Foo');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(1) {
+  ["SimpleAnnotation1"]=>
+  object(SimpleAnnotation1)#%d (1) {
+    ["value":protected]=>
+    array(3) {
+      [0]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        NULL
+      }
+      [1]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        NULL
+        ["value":protected]=>
+        string(4) "test"
+      }
+      [2]=>
+      object(SimpleAnnotation2)#%d (2) {
+        ["foo"]=>
+        string(3) "bar"
+        ["value":protected]=>
+        NULL
+      }
+    }
+  }
+}
Index: tests/annotations/ReflectionProperty_getAnnotations_005.phpt
===================================================================
--- tests/annotations/ReflectionProperty_getAnnotations_005.phpt	(revision 0)
+++ tests/annotations/ReflectionProperty_getAnnotations_005.phpt	(revision 0)
@@ -0,0 +1,25 @@
+--TEST--
+ReflectionProperty::getAnnotations with overrided property 
+--SKIPIF--
+<?php extension_loaded('reflection') or die('skip'); ?>
+--FILE--
+<?php
+
+class SimpleAnnotation extends ReflectionAnnotation {
+}
+
+abstract class Base {
+	[SimpleAnnotation]
+	public $bar;
+}
+class Foo extends Base {
+	public $bar;
+}
+
+$r = new ReflectionProperty('Foo','bar');
+var_dump($r->getAnnotations());
+
+?>
+--EXPECTF--
+array(0) {
+}
