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] = ¶ms; + + 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(¶ms); + } + } + + *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-- + + +--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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + + +--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-- + + +--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-- + + +--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-- + + +--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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +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-- + +--FILE-- +getAnnotations()); + +?> +--EXPECTF-- +array(0) { +}