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) {
+}