--- embedaddon/php/ext/reflection/php_reflection.c 2012/02/21 23:48:00 1.1.1.1 +++ embedaddon/php/ext/reflection/php_reflection.c 2013/10/14 08:02:30 1.1.1.4 @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2012 The PHP Group | + | Copyright (c) 1997-2013 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -20,7 +20,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_reflection.c,v 1.1.1.1 2012/02/21 23:48:00 misho Exp $ */ +/* $Id: php_reflection.c,v 1.1.1.4 2013/10/14 08:02:30 misho Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -39,11 +39,16 @@ #include "zend_ini.h" #include "zend_interfaces.h" #include "zend_closures.h" +#include "zend_extensions.h" -/* Undefine "getParameters" macro defined in "main/php3_compat.h" */ -#ifdef getParameters -# undef getParameters -#endif +#define reflection_update_property(object, name, value) do { \ + zval *member; \ + MAKE_STD_ZVAL(member); \ + ZVAL_STRINGL(member, name, sizeof(name)-1, 1); \ + zend_std_write_property(object, member, value, NULL TSRMLS_CC); \ + Z_DELREF_P(value); \ + zval_ptr_dtor(&member); \ + } while (0) /* Class entry pointers */ PHPAPI zend_class_entry *reflector_ptr; @@ -57,6 +62,7 @@ PHPAPI zend_class_entry *reflection_object_ptr; PHPAPI zend_class_entry *reflection_method_ptr; PHPAPI zend_class_entry *reflection_property_ptr; PHPAPI zend_class_entry *reflection_extension_ptr; +PHPAPI zend_class_entry *reflection_zend_extension_ptr; #if MBO_0 ZEND_BEGIN_MODULE_GLOBALS(reflection) @@ -119,7 +125,7 @@ static void string_init(string *str) str->alloced = 1024; *str->string = '\0'; } - + static string *string_printf(string *str, const char *format, ...) { int len; @@ -172,6 +178,8 @@ static void string_free(string *str) } /* }}} */ +/* {{{ Object structure */ + /* Struct for properties */ typedef struct _property_reference { zend_class_entry *ce; @@ -204,9 +212,11 @@ typedef struct { unsigned int ignore_visibility:1; } reflection_object; +/* }}} */ + static zend_object_handlers reflection_object_handlers; -static void _default_get_entry(zval *object, char *name, int name_len, zval *return_value TSRMLS_DC) +static void _default_get_entry(zval *object, char *name, int name_len, zval *return_value TSRMLS_DC) /* {{{ */ { zval **value; @@ -216,6 +226,7 @@ static void _default_get_entry(zval *object, char *nam MAKE_COPY_ZVAL(value, return_value); } +/* }}} */ #ifdef ilia_0 static void _default_lookup_entry(zval *object, char *name, int name_len, zval **return_value TSRMLS_DC) /* {{{ */ @@ -231,13 +242,14 @@ static void _default_lookup_entry(zval *object, char * /* }}} */ #endif -static void reflection_register_implement(zend_class_entry *class_entry, zend_class_entry *interface_entry TSRMLS_DC) +static void reflection_register_implement(zend_class_entry *class_entry, zend_class_entry *interface_entry TSRMLS_DC) /* {{{ */ { zend_uint num_interfaces = ++class_entry->num_interfaces; class_entry->interfaces = (zend_class_entry **) realloc(class_entry->interfaces, sizeof(zend_class_entry *) * num_interfaces); class_entry->interfaces[num_interfaces - 1] = interface_entry; } +/* }}} */ static zend_function *_copy_function(zend_function *fptr TSRMLS_DC) /* {{{ */ { @@ -263,13 +275,13 @@ static void _free_function(zend_function *fptr TSRMLS_ && fptr->type == ZEND_INTERNAL_FUNCTION && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) { - efree(fptr->internal_function.function_name); + efree((char*)fptr->internal_function.function_name); efree(fptr); } } /* }}} */ -static void reflection_free_objects_storage(void *object TSRMLS_DC) +static void reflection_free_objects_storage(void *object TSRMLS_DC) /* {{{ */ { reflection_object *intern = (reflection_object *) object; parameter_reference *reference; @@ -290,7 +302,7 @@ static void reflection_free_objects_storage(void *obje break; case REF_TYPE_DYNAMIC_PROPERTY: prop_reference = (property_reference*)intern->ptr; - efree(prop_reference->prop.name); + efree((char*)prop_reference->prop.name); efree(intern->ptr); break; case REF_TYPE_OTHER: @@ -303,10 +315,10 @@ static void reflection_free_objects_storage(void *obje } zend_objects_free_object_storage(object TSRMLS_CC); } +/* }}} */ -static zend_object_value reflection_objects_new(zend_class_entry *class_type TSRMLS_DC) +static zend_object_value reflection_objects_new(zend_class_entry *class_type TSRMLS_DC) /* {{{ */ { - zval tmp; zend_object_value retval; reflection_object *intern; @@ -314,13 +326,14 @@ static zend_object_value reflection_objects_new(zend_c intern->zo.ce = class_type; zend_object_std_init(&intern->zo, class_type TSRMLS_CC); - zend_hash_copy(intern->zo.properties, &class_type->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *)); + object_properties_init(&intern->zo, class_type); retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, NULL TSRMLS_CC); retval.handlers = &reflection_object_handlers; return retval; } +/* }}} */ -static zval * reflection_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC) +static zval * reflection_instantiate(zend_class_entry *pce, zval *object TSRMLS_DC) /* {{{ */ { if (!object) { ALLOC_ZVAL(object); @@ -331,36 +344,44 @@ static zval * reflection_instantiate(zend_class_entry Z_SET_ISREF_P(object); return object; } +/* }}} */ static void _const_string(string *str, char *name, zval *value, char *indent TSRMLS_DC); -static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char *indent TSRMLS_DC); +static void _function_string(string *str, zend_function *fptr, zend_class_entry *scope, char* indent TSRMLS_DC); static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent TSRMLS_DC); static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC); static void _extension_string(string *str, zend_module_entry *module, char *indent TSRMLS_DC); +static void _zend_extension_string(string *str, zend_extension *extension, char *indent TSRMLS_DC); /* {{{ _class_string */ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *indent TSRMLS_DC) { int count, count_static_props = 0, count_static_funcs = 0, count_shadow_props = 0; string sub_indent; - + string_init(&sub_indent); string_printf(&sub_indent, "%s ", indent); /* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */ - if (ce->type == ZEND_USER_CLASS && ce->doc_comment) { - string_printf(str, "%s%s", indent, ce->doc_comment); + if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) { + string_printf(str, "%s%s", indent, ce->info.user.doc_comment); string_write(str, "\n", 1); } if (obj) { string_printf(str, "%sObject of class [ ", indent); } else { - string_printf(str, "%s%s [ ", indent, (ce->ce_flags & ZEND_ACC_INTERFACE) ? "Interface" : "Class"); + char *kind = "Class"; + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + kind = "Interface"; + } else if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + kind = "Trait"; + } + string_printf(str, "%s%s [ ", indent, kind); } string_printf(str, (ce->type == ZEND_USER_CLASS) ? "module) { - string_printf(str, ":%s", ce->module->name); + if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module) { + string_printf(str, ":%s", ce->info.internal.module->name); } string_printf(str, "> "); if (ce->get_iterator != NULL) { @@ -368,13 +389,15 @@ static void _class_string(string *str, zend_class_entr } if (ce->ce_flags & ZEND_ACC_INTERFACE) { string_printf(str, "interface "); + } else if ((ce->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) { + string_printf(str, "trait "); } else { if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { string_printf(str, "abstract "); } if (ce->ce_flags & ZEND_ACC_FINAL_CLASS) { string_printf(str, "final "); - } + } string_printf(str, "class "); } string_printf(str, "%s", ce->name); @@ -398,8 +421,8 @@ static void _class_string(string *str, zend_class_entr /* The information where a class is declared is only available for user classes */ if (ce->type == ZEND_USER_CLASS) { - string_printf(str, "%s @@ %s %d-%d\n", indent, ce->filename, - ce->line_start, ce->line_end); + string_printf(str, "%s @@ %s %d-%d\n", indent, ce->info.user.filename, + ce->info.user.line_start, ce->info.user.line_end); } /* Constants */ @@ -429,7 +452,7 @@ static void _class_string(string *str, zend_class_entr /* Static properties */ if (&ce->properties_info) { - /* counting static properties */ + /* counting static properties */ count = zend_hash_num_elements(&ce->properties_info); if (count > 0) { HashPosition pos; @@ -447,7 +470,7 @@ static void _class_string(string *str, zend_class_entr } } - /* static properties */ + /* static properties */ string_printf(str, "\n%s - Static properties [%d] {\n", indent, count_static_props); if (count_static_props > 0) { HashPosition pos; @@ -465,10 +488,10 @@ static void _class_string(string *str, zend_class_entr } string_printf(str, "%s }\n", indent); } - + /* Static methods */ if (&ce->function_table) { - /* counting static methods */ + /* counting static methods */ count = zend_hash_num_elements(&ce->function_table); if (count > 0) { HashPosition pos; @@ -486,7 +509,7 @@ static void _class_string(string *str, zend_class_entr } } - /* static methods */ + /* static methods */ string_printf(str, "\n%s - Static methods [%d] {", indent, count_static_funcs); if (count_static_funcs > 0) { HashPosition pos; @@ -550,7 +573,7 @@ static void _class_string(string *str, zend_class_entr if (prop_name_size && prop_name[0]) { /* skip all private and protected properties */ if (!zend_hash_quick_exists(&ce->properties_info, prop_name, prop_name_size, zend_get_hash_value(prop_name, prop_name_size))) { count++; - _property_string(&dyn, NULL, prop_name, sub_indent.string TSRMLS_CC); + _property_string(&dyn, NULL, prop_name, sub_indent.string TSRMLS_CC); } } efree(prop_name); @@ -621,7 +644,7 @@ static void _class_string(string *str, zend_class_entr } string_printf(str, "%s }\n", indent); } - + string_printf(str, "%s}\n", indent); string_free(&sub_indent); } @@ -659,7 +682,7 @@ static zend_op* _get_recv_op(zend_op_array *op_array, ++offset; while (op < end) { if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT) - && op->op1.u.constant.value.lval == (long)offset) + && op->op1.num == (long)offset) { return op; } @@ -683,8 +706,8 @@ static void _parameter_string(string *str, zend_functi if (arg_info->allow_null) { string_printf(str, "or NULL "); } - } else if (arg_info->array_type_hint) { - string_printf(str, "array "); + } else if (arg_info->type_hint) { + string_printf(str, "%s ", zend_get_type_by_const(arg_info->type_hint)); if (arg_info->allow_null) { string_printf(str, "or NULL "); } @@ -699,12 +722,12 @@ static void _parameter_string(string *str, zend_functi } if (fptr->type == ZEND_USER_FUNCTION && offset >= required) { zend_op *precv = _get_recv_op((zend_op_array*)fptr, offset); - if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2.op_type != IS_UNUSED) { + if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) { zval *zv, zv_copy; int use_copy; string_write(str, " = ", sizeof(" = ")-1); ALLOC_ZVAL(zv); - *zv = precv->op2.u.constant; + *zv = *precv->op2.zv; zval_copy_ctor(zv); INIT_PZVAL(zv); zval_update_constant_ex(&zv, (void*)1, fptr->common.scope TSRMLS_CC); @@ -723,6 +746,8 @@ static void _parameter_string(string *str, zend_functi string_write(str, "...", sizeof("...")-1); } string_write(str, "'", sizeof("'")-1); + } else if (Z_TYPE_P(zv) == IS_ARRAY) { + string_write(str, "Array", sizeof("Array")-1); } else { zend_make_printable_zval(zv, &zv_copy, &use_copy); string_write(str, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy)); @@ -802,7 +827,7 @@ static void _function_string(string *str, zend_functio unsigned int lc_name_len; /* TBD: Repair indenting of doc comment (or is this to be done in the parser?) - * What's "wrong" is that any whitespace before the doc comment start is + * What's "wrong" is that any whitespace before the doc comment start is * swallowed, leading to an unaligned comment. */ if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) { @@ -875,13 +900,13 @@ static void _function_string(string *str, zend_functio string_printf(str, "function "); } - if (fptr->op_array.return_reference) { + if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) { string_printf(str, "&"); } string_printf(str, "%s ] {\n", fptr->common.function_name); /* The information where a function is declared is only available for user classes */ if (fptr->type == ZEND_USER_FUNCTION) { - string_printf(str, "%s @@ %s %d - %d\n", indent, + string_printf(str, "%s @@ %s %d - %d\n", indent, fptr->op_array.filename, fptr->op_array.line_start, fptr->op_array.line_end); @@ -900,7 +925,7 @@ static void _function_string(string *str, zend_functio /* {{{ _property_string */ static void _property_string(string *str, zend_property_info *prop, char *prop_name, char* indent TSRMLS_DC) { - char *class_name; + const char *class_name; string_printf(str, "%sProperty [ ", indent); if (!prop) { @@ -913,7 +938,7 @@ static void _property_string(string *str, zend_propert string_write(str, " ", sizeof(" ") - 1); } } - + /* These are mutually exclusive */ switch (prop->flags & ZEND_ACC_PPP_MASK) { case ZEND_ACC_PUBLIC: @@ -930,7 +955,7 @@ static void _property_string(string *str, zend_propert string_printf(str, "static "); } - zend_unmangle_property_name(prop->name, prop->name_length, &class_name, &prop_name); + zend_unmangle_property_name(prop->name, prop->name_length, &class_name, (const char**)&prop_name); string_printf(str, "$%s", prop_name); } @@ -938,7 +963,7 @@ static void _property_string(string *str, zend_propert } /* }}} */ -static int _extension_ini_string(zend_ini_entry *ini_entry TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +static int _extension_ini_string(zend_ini_entry *ini_entry TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { string *str = va_arg(args, string *); char *indent = va_arg(args, char *); @@ -972,23 +997,25 @@ static int _extension_ini_string(zend_ini_entry *ini_e } return ZEND_HASH_APPLY_KEEP; } +/* }}} */ -static int _extension_class_string(zend_class_entry **pce TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +static int _extension_class_string(zend_class_entry **pce TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { string *str = va_arg(args, string *); char *indent = va_arg(args, char *); struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*); int *num_classes = va_arg(args, int*); - if ((*pce)->module && !strcasecmp((*pce)->module->name, module->name)) { + if (((*pce)->type == ZEND_INTERNAL_CLASS) && (*pce)->info.internal.module && !strcasecmp((*pce)->info.internal.module->name, module->name)) { string_printf(str, "\n"); _class_string(str, *pce, NULL, indent TSRMLS_CC); (*num_classes)++; } return ZEND_HASH_APPLY_KEEP; } +/* }}} */ -static int _extension_const_string(zend_constant *constant TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +static int _extension_const_string(zend_constant *constant TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { string *str = va_arg(args, string *); char *indent = va_arg(args, char *); @@ -1001,6 +1028,7 @@ static int _extension_const_string(zend_constant *cons } return ZEND_HASH_APPLY_KEEP; } +/* }}} */ /* {{{ _extension_string */ static void _extension_string(string *str, zend_module_entry *module, char *indent TSRMLS_DC) @@ -1023,7 +1051,7 @@ static void _extension_string(string *str, zend_module while(dep->name) { string_printf(str, "%s Dependency [ %s (", indent, dep->name); - + switch(dep->type) { case MODULE_DEP_REQUIRED: string_write(str, "Required", sizeof("Required") - 1); @@ -1039,10 +1067,10 @@ static void _extension_string(string *str, zend_module break; } - if (dep->rel) { + if (dep->rel) { string_printf(str, " %s", dep->rel); } - if (dep->version) { + if (dep->version) { string_printf(str, " %s", dep->version); } string_write(str, ") ]\n", sizeof(") ]\n") - 1); @@ -1066,7 +1094,7 @@ static void _extension_string(string *str, zend_module { string str_constants; int num_constants = 0; - + string_init(&str_constants); zend_hash_apply_with_arguments(EG(zend_constants) TSRMLS_CC, (apply_func_args_t) _extension_const_string, 4, &str_constants, indent, module, &num_constants); if (num_constants) { @@ -1087,26 +1115,26 @@ static void _extension_string(string *str, zend_module while (func->fname) { int fname_len = strlen(func->fname); char *lc_name = zend_str_tolower_dup(func->fname, fname_len); - - if (zend_hash_find(EG(function_table), lc_name, fname_len+1, (void**) &fptr) == FAILURE) { + + if (zend_hash_find(EG(function_table), lc_name, fname_len + 1, (void**) &fptr) == FAILURE) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Internal error: Cannot find extension function %s in global function table", func->fname); func++; efree(lc_name); continue; } - + _function_string(str, fptr, NULL, " " TSRMLS_CC); efree(lc_name); func++; } string_printf(str, "%s }\n", indent); } - + { string str_classes; string sub_indent; int num_classes = 0; - + string_init(&sub_indent); string_printf(&sub_indent, "%s ", indent); string_init(&str_classes); @@ -1124,6 +1152,27 @@ static void _extension_string(string *str, zend_module } /* }}} */ +static void _zend_extension_string(string *str, zend_extension *extension, char *indent TSRMLS_DC) /* {{{ */ +{ + string_printf(str, "%sZend Extension [ %s ", indent, extension->name); + + if (extension->version) { + string_printf(str, "%s ", extension->version); + } + if (extension->copyright) { + string_printf(str, "%s ", extension->copyright); + } + if (extension->author) { + string_printf(str, "by %s ", extension->author); + } + if (extension->URL) { + string_printf(str, "<%s> ", extension->URL); + } + + string_printf(str, "]\n"); +} +/* }}} */ + /* {{{ _function_check_flag */ static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) { @@ -1151,7 +1200,7 @@ PHPAPI void zend_reflection_class_factory(zend_class_e intern->ptr = ce; intern->ref_type = REF_TYPE_OTHER; intern->ce = ce; - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); } /* }}} */ @@ -1180,7 +1229,7 @@ static void reflection_extension_factory(zval *object, intern->ptr = module; intern->ref_type = REF_TYPE_OTHER; intern->ce = NULL; - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); } /* }}} */ @@ -1211,7 +1260,7 @@ static void reflection_parameter_factory(zend_function intern->ref_type = REF_TYPE_PARAMETER; intern->ce = fptr->common.scope; intern->obj = closure_object; - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); } /* }}} */ @@ -1233,7 +1282,7 @@ static void reflection_function_factory(zend_function intern->ref_type = REF_TYPE_FUNCTION; intern->ce = NULL; intern->obj = closure_object; - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); } /* }}} */ @@ -1249,7 +1298,8 @@ static void reflection_method_factory(zend_class_entry } MAKE_STD_ZVAL(name); MAKE_STD_ZVAL(classname); - ZVAL_STRING(name, method->common.function_name, 1); + ZVAL_STRING(name, (method->common.scope && method->common.scope->trait_aliases)? + zend_resolve_method_name(ce, method) : method->common.function_name, 1); ZVAL_STRINGL(classname, method->common.scope->name, method->common.scope->name_length, 1); reflection_instantiate(reflection_method_ptr, object TSRMLS_CC); intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); @@ -1257,8 +1307,8 @@ static void reflection_method_factory(zend_class_entry intern->ref_type = REF_TYPE_FUNCTION; intern->ce = ce; intern->obj = closure_object; - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); - zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); + reflection_update_property(object, "class", classname); } /* }}} */ @@ -1269,7 +1319,7 @@ static void reflection_property_factory(zend_class_ent zval *name; zval *classname; property_reference *reference; - char *class_name, *prop_name; + const char *class_name, *prop_name; zend_unmangle_property_name(prop->name, prop->name_length, &class_name, &prop_name); @@ -1304,8 +1354,8 @@ static void reflection_property_factory(zend_class_ent intern->ref_type = REF_TYPE_PROPERTY; intern->ce = ce; intern->ignore_visibility = 0; - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); - zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); + reflection_update_property(object, "class", classname); } /* }}} */ @@ -1361,7 +1411,7 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAM fcc.object_ptr = reflector_ptr; result = zend_call_function(&fci, &fcc TSRMLS_CC); - + if (retval_ptr) { zval_ptr_dtor(&retval_ptr); } @@ -1408,6 +1458,49 @@ static void _reflection_export(INTERNAL_FUNCTION_PARAM } /* }}} */ +/* {{{ _reflection_param_get_default_param */ +static parameter_reference *_reflection_param_get_default_param(INTERNAL_FUNCTION_PARAMETERS) +{ + reflection_object *intern; + parameter_reference *param; + + intern = (reflection_object *) zend_object_store_get_object(getThis() TSRMLS_CC); + if (intern == NULL || intern->ptr == NULL) { + if (EG(exception) && Z_OBJCE_P(EG(exception)) == reflection_exception_ptr) { + return NULL; + } + php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Failed to retrieve the reflection object"); + } + + param = intern->ptr; + if (param->fptr->type != ZEND_USER_FUNCTION) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot determine default value for internal functions"); + return NULL; + } + + return param; +} +/* }}} */ + +/* {{{ _reflection_param_get_default_precv */ +static zend_op *_reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAMETERS, parameter_reference *param) +{ + zend_op *precv; + + if (param == NULL) { + return NULL; + } + + precv = _get_recv_op((zend_op_array*)param->fptr, param->offset); + if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error: Failed to retrieve the default value"); + return NULL; + } + + return precv; +} +/* }}} */ + /* {{{ Preventing __clone from being called */ ZEND_METHOD(reflection, __clone) { @@ -1536,10 +1629,10 @@ ZEND_METHOD(reflection_function, __construct) nsname = &lcname[1]; name_len--; } - + if (zend_hash_find(EG(function_table), nsname, name_len + 1, (void **)&fptr) == FAILURE) { efree(lcname); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Function %s() does not exist", name_str); return; } @@ -1550,7 +1643,7 @@ ZEND_METHOD(reflection_function, __construct) MAKE_STD_ZVAL(name); ZVAL_STRING(name, fptr->common.function_name, 1); - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); intern->ptr = fptr; intern->ref_type = REF_TYPE_FUNCTION; intern->obj = closure; @@ -1602,6 +1695,65 @@ ZEND_METHOD(reflection_function, isClosure) } /* }}} */ +/* {{{ proto public bool ReflectionFunction::getClosureThis() + Returns this pointer bound to closure */ +ZEND_METHOD(reflection_function, getClosureThis) +{ + reflection_object *intern; + zend_function *fptr; + zval* closure_this; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(fptr); + if (intern->obj) { + closure_this = zend_get_closure_this_ptr(intern->obj TSRMLS_CC); + if (closure_this) { + RETURN_ZVAL(closure_this, 1, 0); + } + } +} +/* }}} */ + +/* {{{ proto public ReflectionClass ReflectionFunction::getClosureScopeClass() + Returns the scope associated to the closure */ +ZEND_METHOD(reflection_function, getClosureScopeClass) +{ + reflection_object *intern; + zend_function *fptr; + const zend_function *closure_func; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(fptr); + if (intern->obj) { + closure_func = zend_get_closure_method_def(intern->obj TSRMLS_CC); + if (closure_func && closure_func->common.scope) { + zend_reflection_class_factory(closure_func->common.scope, return_value TSRMLS_CC); + } + } +} +/* }}} */ + +/* {{{ proto public mixed ReflectionFunction::getClosure() + Returns a dynamically created closure for the function */ +ZEND_METHOD(reflection_function, getClosure) +{ + reflection_object *intern; + zend_function *fptr; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(fptr); + + zend_create_closure(return_value, fptr, NULL, NULL TSRMLS_CC); +} +/* }}} */ + + /* {{{ proto public bool ReflectionFunction::isInternal() Returns whether this is an internal function */ ZEND_METHOD(reflection_function, isInternal) @@ -1724,7 +1876,7 @@ ZEND_METHOD(reflection_function, getStaticVariables) zval *tmp_copy; reflection_object *intern; zend_function *fptr; - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -1733,7 +1885,7 @@ ZEND_METHOD(reflection_function, getStaticVariables) /* Return an empty array in case no static variables exist */ array_init(return_value); if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) { - zend_hash_apply_with_argument(fptr->op_array.static_variables, (apply_func_arg_t) zval_update_constant, (void*)1 TSRMLS_CC); + zend_hash_apply_with_argument(fptr->op_array.static_variables, (apply_func_arg_t) zval_update_constant_inline_change, fptr->common.scope TSRMLS_CC); zend_hash_copy(Z_ARRVAL_P(return_value), fptr->op_array.static_variables, (copy_ctor_func_t) zval_add_ref, (void *) &tmp_copy, sizeof(zval *)); } } @@ -1750,7 +1902,7 @@ ZEND_METHOD(reflection_function, invoke) zend_fcall_info_cache fcc; reflection_object *intern; zend_function *fptr; - + METHOD_NOTSTATIC(reflection_function_ptr); GET_REFLECTION_OBJECT_PTR(fptr); @@ -1781,7 +1933,7 @@ ZEND_METHOD(reflection_function, invoke) } if (result == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Invocation of function %s() failed", fptr->common.function_name); return; } @@ -1811,7 +1963,7 @@ ZEND_METHOD(reflection_function, invokeArgs) reflection_object *intern; zend_function *fptr; zval *param_array; - + METHOD_NOTSTATIC(reflection_function_ptr); GET_REFLECTION_OBJECT_PTR(fptr); @@ -1820,9 +1972,9 @@ ZEND_METHOD(reflection_function, invokeArgs) } argc = zend_hash_num_elements(Z_ARRVAL_P(param_array)); - + params = safe_emalloc(sizeof(zval **), argc, 0); - zend_hash_apply_with_argument(Z_ARRVAL_P(param_array), (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC); + zend_hash_apply_with_argument(Z_ARRVAL_P(param_array), (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC); params -= argc; fci.size = sizeof(fci); @@ -1846,7 +1998,7 @@ ZEND_METHOD(reflection_function, invokeArgs) efree(params); if (result == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Invocation of function %s() failed", fptr->common.function_name); return; } @@ -1867,7 +2019,7 @@ ZEND_METHOD(reflection_function, returnsReference) METHOD_NOTSTATIC(reflection_function_abstract_ptr); GET_REFLECTION_OBJECT_PTR(fptr); - RETURN_BOOL(fptr->op_array.return_reference); + RETURN_BOOL((fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0); } /* }}} */ @@ -1915,7 +2067,7 @@ ZEND_METHOD(reflection_function, getParameters) array_init(return_value); for (i = 0; i < fptr->common.num_args; i++) { - zval *parameter; + zval *parameter; ALLOC_ZVAL(parameter); reflection_parameter_factory(_copy_function(fptr TSRMLS_CC), intern->obj, arg_info, i, fptr->common.required_num_args, parameter TSRMLS_CC); @@ -2006,7 +2158,7 @@ ZEND_METHOD(reflection_parameter, __construct) if (intern == NULL) { return; } - + /* First, find the function */ switch (Z_TYPE_P(reference)) { case IS_STRING: { @@ -2017,7 +2169,7 @@ ZEND_METHOD(reflection_parameter, __construct) lcname = zend_str_tolower_dup(Z_STRVAL_P(reference), lcname_len); if (zend_hash_find(EG(function_table), lcname, lcname_len + 1, (void**) &fptr) == FAILURE) { efree(lcname); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Function %s() does not exist", Z_STRVAL_P(reference)); return; } @@ -2032,7 +2184,7 @@ ZEND_METHOD(reflection_parameter, __construct) zend_class_entry **pce; unsigned int lcname_len; char *lcname; - + if ((zend_hash_index_find(Z_ARRVAL_P(reference), 0, (void **) &classref) == FAILURE) || (zend_hash_index_find(Z_ARRVAL_P(reference), 1, (void **) &method) == FAILURE)) { @@ -2051,7 +2203,7 @@ ZEND_METHOD(reflection_parameter, __construct) } ce = *pce; } - + convert_to_string_ex(method); lcname_len = Z_STRLEN_PP(method); lcname = zend_str_tolower_dup(Z_STRVAL_PP(method), lcname_len); @@ -2060,21 +2212,21 @@ ZEND_METHOD(reflection_parameter, __construct) && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 && (fptr = zend_get_closure_invoke_method(*classref TSRMLS_CC)) != NULL) { - /* nothign to do. don't set is_closure since is the invoke handler, - not the closure itself */ + /* nothing to do. don't set is_closure since is the invoke handler, +- not the closure itself */ } else if (zend_hash_find(&ce->function_table, lcname, lcname_len + 1, (void **) &fptr) == FAILURE) { efree(lcname); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Method %s::%s() does not exist", ce->name, Z_STRVAL_PP(method)); return; } efree(lcname); } break; - + case IS_OBJECT: { ce = Z_OBJCE_P(reference); - + if (instanceof_function(ce, zend_ce_closure TSRMLS_CC)) { fptr = (zend_function *)zend_get_closure_method_def(reference TSRMLS_CC); Z_ADDREF_P(reference); @@ -2086,12 +2238,12 @@ ZEND_METHOD(reflection_parameter, __construct) } } break; - + default: _DO_THROW("The parameter class is expected to be either a string, an array(class, method) or a callable object"); /* returns out of this function */ } - + /* Now, search for the parameter */ arg_info = fptr->common.arg_info; if (Z_TYPE_PP(parameter) == IS_LONG) { @@ -2099,7 +2251,7 @@ ZEND_METHOD(reflection_parameter, __construct) if (position < 0 || (zend_uint)position >= fptr->common.num_args) { if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) { if (fptr->type != ZEND_OVERLOADED_FUNCTION) { - efree(fptr->common.function_name); + efree((char*)fptr->common.function_name); } efree(fptr); } @@ -2123,7 +2275,7 @@ ZEND_METHOD(reflection_parameter, __construct) if (position == -1) { if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) { if (fptr->type != ZEND_OVERLOADED_FUNCTION) { - efree(fptr->common.function_name); + efree((char*)fptr->common.function_name); } efree(fptr); } @@ -2134,14 +2286,14 @@ ZEND_METHOD(reflection_parameter, __construct) /* returns out of this function */ } } - + MAKE_STD_ZVAL(name); if (arg_info[position].name) { ZVAL_STRINGL(name, arg_info[position].name, arg_info[position].name_len, 1); } else { ZVAL_NULL(name); } - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); ref = (parameter_reference*) emalloc(sizeof(parameter_reference)); ref->arg_info = &arg_info[position]; @@ -2221,7 +2373,7 @@ ZEND_METHOD(reflection_parameter, getDeclaringClass) if (param->fptr->common.scope) { zend_reflection_class_factory(param->fptr->common.scope, return_value TSRMLS_CC); - } + } } /* }}} */ @@ -2251,29 +2403,29 @@ ZEND_METHOD(reflection_parameter, getClass) * TODO: Think about moving these checks to the compiler or some sort of * lint-mode. */ - if (0 == strncmp(param->arg_info->class_name, "self", sizeof("self")- 1)) { + if (0 == zend_binary_strcasecmp(param->arg_info->class_name, param->arg_info->class_name_len, "self", sizeof("self")- 1)) { ce = param->fptr->common.scope; if (!ce) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter uses 'self' as type hint but function is not a class member!"); return; } pce= &ce; - } else if (0 == strncmp(param->arg_info->class_name, "parent", sizeof("parent")- 1)) { + } else if (0 == zend_binary_strcasecmp(param->arg_info->class_name, param->arg_info->class_name_len, "parent", sizeof("parent")- 1)) { ce = param->fptr->common.scope; if (!ce) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter uses 'parent' as type hint but function is not a class member!"); return; } if (!ce->parent) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter uses 'parent' as type hint although class does not have a parent!"); return; } pce= &ce->parent; } else if (zend_lookup_class(param->arg_info->class_name, param->arg_info->class_name_len, &pce TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not exist", param->arg_info->class_name); return; } @@ -2294,10 +2446,26 @@ ZEND_METHOD(reflection_parameter, isArray) } GET_REFLECTION_OBJECT_PTR(param); - RETVAL_BOOL(param->arg_info->array_type_hint); + RETVAL_BOOL(param->arg_info->type_hint == IS_ARRAY); } /* }}} */ +/* {{{ proto public bool ReflectionParameter::isCallable() + Returns whether parameter MUST be callable */ +ZEND_METHOD(reflection_parameter, isCallable) +{ + reflection_object *intern; + parameter_reference *param; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(param); + + RETVAL_BOOL(param->arg_info->type_hint == IS_CALLABLE); +} +/* }}} */ + /* {{{ proto public bool ReflectionParameter::allowsNull() Returns whether NULL is allowed as this parameters's value */ ZEND_METHOD(reflection_parameter, allowsNull) @@ -2330,6 +2498,23 @@ ZEND_METHOD(reflection_parameter, isPassedByReference) } /* }}} */ +/* {{{ proto public bool ReflectionParameter::canBePassedByValue() + Returns whether this parameter can be passed by value */ +ZEND_METHOD(reflection_parameter, canBePassedByValue) +{ + reflection_object *intern; + parameter_reference *param; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(param); + + /* true if it's ZEND_SEND_BY_VAL or ZEND_SEND_PREFER_REF */ + RETVAL_BOOL(param->arg_info->pass_by_reference != ZEND_SEND_BY_REF); +} +/* }}} */ + /* {{{ proto public bool ReflectionParameter::getPosition() Returns whether this parameter is an optional parameter */ ZEND_METHOD(reflection_parameter, getPosition) @@ -2379,11 +2564,9 @@ ZEND_METHOD(reflection_parameter, isDefaultValueAvaila { RETURN_FALSE; } - if (param->offset < param->required) { - RETURN_FALSE; - } + precv = _get_recv_op((zend_op_array*)param->fptr, param->offset); - if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { + if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2_type == IS_UNUSED) { RETURN_FALSE; } RETURN_TRUE; @@ -2394,39 +2577,81 @@ ZEND_METHOD(reflection_parameter, isDefaultValueAvaila Returns the default value of this parameter or throws an exception */ ZEND_METHOD(reflection_parameter, getDefaultValue) { - reflection_object *intern; parameter_reference *param; zend_op *precv; if (zend_parse_parameters_none() == FAILURE) { return; } - GET_REFLECTION_OBJECT_PTR(param); - if (param->fptr->type != ZEND_USER_FUNCTION) - { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot determine default value for internal functions"); + param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU); + if (!param) { return; } - if (param->offset < param->required) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional"); + + precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param); + if (!precv) { return; } - precv = _get_recv_op((zend_op_array*)param->fptr, param->offset); - if (!precv || precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error"); - return; - } - *return_value = precv->op2.u.constant; + *return_value = *precv->op2.zv; INIT_PZVAL(return_value); - if (Z_TYPE_P(return_value) != IS_CONSTANT && Z_TYPE_P(return_value) != IS_CONSTANT_ARRAY) { + if ((Z_TYPE_P(return_value) & IS_CONSTANT_TYPE_MASK) != IS_CONSTANT + && (Z_TYPE_P(return_value) & IS_CONSTANT_TYPE_MASK) != IS_CONSTANT_ARRAY) { zval_copy_ctor(return_value); } zval_update_constant_ex(&return_value, (void*)0, param->fptr->common.scope TSRMLS_CC); } /* }}} */ +/* {{{ proto public bool ReflectionParameter::isDefaultValueConstant() + Returns whether the default value of this parameter is constant */ +ZEND_METHOD(reflection_parameter, isDefaultValueConstant) +{ + zend_op *precv; + parameter_reference *param; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU); + if (!param) { + RETURN_FALSE; + } + + precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param); + if (precv && (Z_TYPE_P(precv->op2.zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + RETURN_TRUE; + } + + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto public mixed ReflectionParameter::getDefaultValueConstantName() + Returns the default value's constant name if default value is constant or null */ +ZEND_METHOD(reflection_parameter, getDefaultValueConstantName) +{ + zend_op *precv; + parameter_reference *param; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + param = _reflection_param_get_default_param(INTERNAL_FUNCTION_PARAM_PASSTHRU); + if (!param) { + return; + } + + precv = _reflection_param_get_default_precv(INTERNAL_FUNCTION_PARAM_PASSTHRU, param); + if (precv && (Z_TYPE_P(precv->op2.zv) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + RETURN_STRINGL(Z_STRVAL_P(precv->op2.zv), Z_STRLEN_P(precv->op2.zv), 1); + } +} +/* }}} */ + /* {{{ 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) @@ -2455,7 +2680,7 @@ ZEND_METHOD(reflection_method, __construct) return; } if ((tmp = strstr(name_str, "::")) == NULL) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Invalid method name %s", name_str); + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Invalid method name %s", name_str); return; } classname = &ztmp; @@ -2475,13 +2700,13 @@ ZEND_METHOD(reflection_method, __construct) if (intern == NULL) { return; } - + /* Find the class entry */ switch (Z_TYPE_P(classname)) { case IS_STRING: if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", Z_STRVAL_P(classname)); + "Class %s does not exist", Z_STRVAL_P(classname)); if (classname == &ztmp) { zval_dtor(&ztmp); } @@ -2515,7 +2740,7 @@ ZEND_METHOD(reflection_method, __construct) /* do nothing, mptr already set */ } else if (zend_hash_find(&ce->function_table, lcname, name_len + 1, (void **) &mptr) == FAILURE) { efree(lcname); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Method %s::%s() does not exist", ce->name, name_str); return; } @@ -2524,11 +2749,11 @@ ZEND_METHOD(reflection_method, __construct) MAKE_STD_ZVAL(classname); ZVAL_STRINGL(classname, mptr->common.scope->name, mptr->common.scope->name_length, 1); - zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); - + reflection_update_property(object, "class", classname); + MAKE_STD_ZVAL(name); ZVAL_STRING(name, mptr->common.function_name, 1); - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property(object, "name", name); intern->ptr = mptr; intern->ref_type = REF_TYPE_FUNCTION; intern->ce = ce; @@ -2553,6 +2778,41 @@ ZEND_METHOD(reflection_method, __toString) } /* }}} */ +/* {{{ proto public mixed ReflectionMethod::getClosure([mixed object]) + Invokes the function */ +ZEND_METHOD(reflection_method, getClosure) +{ + reflection_object *intern; + zval *obj; + zend_function *mptr; + + METHOD_NOTSTATIC(reflection_method_ptr); + GET_REFLECTION_OBJECT_PTR(mptr); + + if (mptr->common.fn_flags & ZEND_ACC_STATIC) { + zend_create_closure(return_value, mptr, mptr->common.scope, NULL TSRMLS_CC); + } else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &obj) == FAILURE) { + return; + } + + if (!instanceof_function(Z_OBJCE_P(obj), mptr->common.scope TSRMLS_CC)) { + _DO_THROW("Given object is not an instance of the class this method was declared in"); + /* Returns from this function */ + } + + /* This is an original closure object and __invoke is to be called. */ + if (Z_OBJCE_P(obj) == zend_ce_closure && mptr->type == ZEND_INTERNAL_FUNCTION && + (mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) + { + RETURN_ZVAL(obj, 1, 0); + } else { + zend_create_closure(return_value, mptr, mptr->common.scope, obj TSRMLS_CC); + } + } +} +/* }}} */ + /* {{{ proto public mixed ReflectionMethod::invoke(mixed object, mixed* args) Invokes the method. */ ZEND_METHOD(reflection_method, invoke) @@ -2566,7 +2826,7 @@ ZEND_METHOD(reflection_method, invoke) zend_fcall_info fci; zend_fcall_info_cache fcc; zend_class_entry *obj_ce; - + METHOD_NOTSTATIC(reflection_method_ptr); GET_REFLECTION_OBJECT_PTR(mptr); @@ -2576,12 +2836,12 @@ ZEND_METHOD(reflection_method, invoke) && intern->ignore_visibility == 0) { if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke abstract method %s::%s()", + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + "Trying to invoke abstract method %s::%s()", mptr->common.scope->name, mptr->common.function_name); } else { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke %s method %s::%s() from scope %s", + "Trying to invoke %s method %s::%s() from scope %s", mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private", mptr->common.scope->name, mptr->common.function_name, Z_OBJCE_P(getThis())->name); @@ -2592,7 +2852,7 @@ ZEND_METHOD(reflection_method, invoke) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", ¶ms, &num_args) == FAILURE) { return; } - + /* In case this is a static method, we should'nt pass an object_ptr * (which is used as calling context aka $this). We can thus ignore the * first parameter. @@ -2618,10 +2878,10 @@ ZEND_METHOD(reflection_method, invoke) _DO_THROW("Given object is not an instance of the class this method was declared in"); /* Returns from this function */ } - + object_ptr = *params[0]; } - + fci.size = sizeof(fci); fci.function_table = NULL; fci.function_name = NULL; @@ -2639,13 +2899,13 @@ ZEND_METHOD(reflection_method, invoke) fcc.object_ptr = object_ptr; result = zend_call_function(&fci, &fcc TSRMLS_CC); - + if (params) { efree(params); } if (result == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2671,7 +2931,7 @@ ZEND_METHOD(reflection_method, invokeArgs) zend_fcall_info_cache fcc; zend_class_entry *obj_ce; zval *param_array; - + METHOD_NOTSTATIC(reflection_method_ptr); GET_REFLECTION_OBJECT_PTR(mptr); @@ -2685,12 +2945,12 @@ ZEND_METHOD(reflection_method, invokeArgs) && intern->ignore_visibility == 0) { if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke abstract method %s::%s()", + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + "Trying to invoke abstract method %s::%s()", mptr->common.scope->name, mptr->common.function_name); } else { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke %s method %s::%s() from scope %s", + "Trying to invoke %s method %s::%s() from scope %s", mptr->common.fn_flags & ZEND_ACC_PROTECTED ? "protected" : "private", mptr->common.scope->name, mptr->common.function_name, Z_OBJCE_P(getThis())->name); @@ -2699,11 +2959,11 @@ ZEND_METHOD(reflection_method, invokeArgs) } argc = zend_hash_num_elements(Z_ARRVAL_P(param_array)); - + params = safe_emalloc(sizeof(zval **), argc, 0); - zend_hash_apply_with_argument(Z_ARRVAL_P(param_array), (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC); + zend_hash_apply_with_argument(Z_ARRVAL_P(param_array), (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC); params -= argc; - + /* In case this is a static method, we should'nt pass an object_ptr * (which is used as calling context aka $this). We can thus ignore the * first parameter. @@ -2717,11 +2977,11 @@ ZEND_METHOD(reflection_method, invokeArgs) if (!object) { efree(params); zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Trying to invoke non static method %s::%s() without an object", + "Trying to invoke non static method %s::%s() without an object", mptr->common.scope->name, mptr->common.function_name); return; } - + obj_ce = Z_OBJCE_P(object); if (!instanceof_function(obj_ce, mptr->common.scope TSRMLS_CC)) { @@ -2730,7 +2990,7 @@ ZEND_METHOD(reflection_method, invokeArgs) /* Returns from this function */ } } - + fci.size = sizeof(fci); fci.function_table = NULL; fci.function_name = NULL; @@ -2744,15 +3004,23 @@ ZEND_METHOD(reflection_method, invokeArgs) fcc.initialized = 1; fcc.function_handler = mptr; fcc.calling_scope = obj_ce; - fcc.called_scope = obj_ce; + fcc.called_scope = intern->ce; fcc.object_ptr = object; + + /* + * Copy the zend_function when calling via handler (e.g. Closure::__invoke()) + */ + if (mptr->type == ZEND_INTERNAL_FUNCTION && + (mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0) { + fcc.function_handler = _copy_function(mptr TSRMLS_CC); + } result = zend_call_function(&fci, &fcc TSRMLS_CC); - + efree(params); if (result == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Invocation of method %s::%s() failed", mptr->common.scope->name, mptr->common.function_name); return; } @@ -2824,7 +3092,7 @@ ZEND_METHOD(reflection_function, isDeprecated) ZEND_METHOD(reflection_function, inNamespace) { zval **name; - char *colon; + const char *backslash; if (zend_parse_parameters_none() == FAILURE) { return; @@ -2833,8 +3101,8 @@ ZEND_METHOD(reflection_function, inNamespace) RETURN_FALSE; } if (Z_TYPE_PP(name) == IS_STRING - && (colon = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name))) - && colon > Z_STRVAL_PP(name)) + && (backslash = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name))) + && backslash > Z_STRVAL_PP(name)) { RETURN_TRUE; } @@ -2847,7 +3115,7 @@ ZEND_METHOD(reflection_function, inNamespace) ZEND_METHOD(reflection_function, getNamespaceName) { zval **name; - char *backslash; + const char *backslash; if (zend_parse_parameters_none() == FAILURE) { return; @@ -2870,7 +3138,7 @@ ZEND_METHOD(reflection_function, getNamespaceName) ZEND_METHOD(reflection_function, getShortName) { zval **name; - char *backslash; + const char *backslash; if (zend_parse_parameters_none() == FAILURE) { return; @@ -2899,7 +3167,7 @@ ZEND_METHOD(reflection_method, isConstructor) return; } GET_REFLECTION_OBJECT_PTR(mptr); - /* we need to check if the ctor is the ctor of the class level we we + /* we need to check if the ctor is the ctor of the class level we we * looking at since we might be looking at an inherited old style ctor * defined in base class. */ RETURN_BOOL(mptr->common.fn_flags & ZEND_ACC_CTOR && intern->ce->constructor && intern->ce->constructor->common.scope == mptr->common.scope); @@ -2946,7 +3214,7 @@ ZEND_METHOD(reflection_method, getDeclaringClass) METHOD_NOTSTATIC(reflection_method_ptr); GET_REFLECTION_OBJECT_PTR(mptr); - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -2964,13 +3232,13 @@ ZEND_METHOD(reflection_method, getPrototype) METHOD_NOTSTATIC(reflection_method_ptr); GET_REFLECTION_OBJECT_PTR(mptr); - + if (zend_parse_parameters_none() == FAILURE) { return; } - + if (!mptr->common.prototype) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Method %s::%s does not have a prototype", intern->ce->name, mptr->common.function_name); return; } @@ -3032,17 +3300,17 @@ static void reflection_class_object_ctor(INTERNAL_FUNC if (intern == NULL) { return; } - + if (Z_TYPE_P(argument) == IS_OBJECT) { MAKE_STD_ZVAL(classname); ZVAL_STRINGL(classname, Z_OBJCE_P(argument)->name, Z_OBJCE_P(argument)->name_length, 1); - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); + reflection_update_property(object, "name", classname); intern->ptr = Z_OBJCE_P(argument); if (is_object) { intern->obj = argument; zval_add_ref(&argument); } - } else { + } else { convert_to_string_ex(&argument); if (zend_lookup_class(Z_STRVAL_P(argument), Z_STRLEN_P(argument), &ce TSRMLS_CC) == FAILURE) { if (!EG(exception)) { @@ -3053,7 +3321,7 @@ static void reflection_class_object_ctor(INTERNAL_FUNC MAKE_STD_ZVAL(classname); ZVAL_STRINGL(classname, (*ce)->name, (*ce)->name_length, 1); - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &classname, sizeof(zval *), NULL); + reflection_update_property(object, "name", classname); intern->ptr = *ce; } @@ -3069,49 +3337,74 @@ ZEND_METHOD(reflection_class, __construct) } /* }}} */ +/* {{{ add_class_vars */ +static void add_class_vars(zend_class_entry *ce, int statics, zval *return_value TSRMLS_DC) +{ + HashPosition pos; + zend_property_info *prop_info; + zval *prop, *prop_copy; + char *key; + uint key_len; + ulong num_index; + + zend_hash_internal_pointer_reset_ex(&ce->properties_info, &pos); + while (zend_hash_get_current_data_ex(&ce->properties_info, (void **) &prop_info, &pos) == SUCCESS) { + zend_hash_get_current_key_ex(&ce->properties_info, &key, &key_len, &num_index, 0, &pos); + zend_hash_move_forward_ex(&ce->properties_info, &pos); + if (((prop_info->flags & ZEND_ACC_SHADOW) && + prop_info->ce != ce) || + ((prop_info->flags & ZEND_ACC_PROTECTED) && + !zend_check_protected(prop_info->ce, ce)) || + ((prop_info->flags & ZEND_ACC_PRIVATE) && + prop_info->ce != ce)) { + continue; + } + prop = NULL; + if (prop_info->offset >= 0) { + if (statics && (prop_info->flags & ZEND_ACC_STATIC) != 0) { + prop = ce->default_static_members_table[prop_info->offset]; + } else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) { + prop = ce->default_properties_table[prop_info->offset]; + } + } + if (!prop) { + continue; + } + + /* copy: enforce read only access */ + ALLOC_ZVAL(prop_copy); + *prop_copy = *prop; + zval_copy_ctor(prop_copy); + INIT_PZVAL(prop_copy); + + /* this is necessary to make it able to work with default array + * properties, returned to user */ + if (Z_TYPE_P(prop_copy) == IS_CONSTANT_ARRAY || (Z_TYPE_P(prop_copy) & IS_CONSTANT_TYPE_MASK) == IS_CONSTANT) { + zval_update_constant(&prop_copy, (void *) 1 TSRMLS_CC); + } + + add_assoc_zval(return_value, key, prop_copy); + } +} +/* }}} */ + /* {{{ proto public array ReflectionClass::getStaticProperties() Returns an associative array containing all static property values of the class */ ZEND_METHOD(reflection_class, getStaticProperties) { reflection_object *intern; zend_class_entry *ce; - HashPosition pos; - zval **value; if (zend_parse_parameters_none() == FAILURE) { return; } - + GET_REFLECTION_OBJECT_PTR(ce); zend_update_class_constants(ce TSRMLS_CC); array_init(return_value); - - zend_hash_internal_pointer_reset_ex(CE_STATIC_MEMBERS(ce), &pos); - - while (zend_hash_get_current_data_ex(CE_STATIC_MEMBERS(ce), (void **) &value, &pos) == SUCCESS) { - uint key_len; - char *key; - ulong num_index; - - if (zend_hash_get_current_key_ex(CE_STATIC_MEMBERS(ce), &key, &key_len, &num_index, 0, &pos) != FAILURE && key) { - char *prop_name, *class_name; - zval *prop_copy; - - zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name); - - /* filter privates from base classes */ - if (!(class_name && class_name[0] != '*' && strcmp(class_name, ce->name))) { - /* copy: enforce read only access */ - ALLOC_ZVAL(prop_copy); - MAKE_COPY_ZVAL(value, prop_copy); - - add_assoc_zval(return_value, prop_name, prop_copy); - } - } - zend_hash_move_forward_ex(CE_STATIC_MEMBERS(ce), &pos); - } + add_class_vars(ce, 1, return_value TSRMLS_CC); } /* }}} */ @@ -3124,7 +3417,7 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue) char *name; int name_len; zval **prop, *def_value = NULL; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &name, &name_len, &def_value) == FAILURE) { return; } @@ -3132,12 +3425,12 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue) GET_REFLECTION_OBJECT_PTR(ce); zend_update_class_constants(ce TSRMLS_CC); - prop = zend_std_get_static_property(ce, name, name_len, 1 TSRMLS_CC); + prop = zend_std_get_static_property(ce, name, name_len, 1, NULL TSRMLS_CC); if (!prop) { if (def_value) { RETURN_ZVAL(def_value, 1, 0); } else { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not have a property named %s", ce->name, name); } return; @@ -3158,7 +3451,7 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) zval **variable_ptr, *value; int refcount; zend_uchar is_ref; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &name, &name_len, &value) == FAILURE) { return; } @@ -3166,12 +3459,12 @@ ZEND_METHOD(reflection_class, setStaticPropertyValue) GET_REFLECTION_OBJECT_PTR(ce); zend_update_class_constants(ce TSRMLS_CC); - variable_ptr = zend_std_get_static_property(ce, name, name_len, 1 TSRMLS_CC); + variable_ptr = zend_std_get_static_property(ce, name, name_len, 1, NULL TSRMLS_CC); if (!variable_ptr) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not have a property named %s", ce->name, name); return; - } + } refcount = Z_REFCOUNT_PP(variable_ptr); is_ref = Z_ISREF_PP(variable_ptr); zval_dtor(*variable_ptr); @@ -3189,51 +3482,15 @@ ZEND_METHOD(reflection_class, getDefaultProperties) { reflection_object *intern; zend_class_entry *ce; - int count, i; - HashTable *ht_list[3]; - + if (zend_parse_parameters_none() == FAILURE) { return; } GET_REFLECTION_OBJECT_PTR(ce); array_init(return_value); - zend_update_class_constants(ce TSRMLS_CC); - - ht_list[0] = CE_STATIC_MEMBERS(ce); - ht_list[1] = &ce->default_properties; - ht_list[2] = NULL; - - for (i = 0; ht_list[i] != NULL; i++) { - - count = zend_hash_num_elements(ht_list[i]); - if (count > 0) { - HashPosition pos; - zval **prop; - - zend_hash_internal_pointer_reset_ex(ht_list[i], &pos); - while (zend_hash_get_current_data_ex(ht_list[i], (void **) &prop, &pos) == SUCCESS) { - char *key, *class_name, *prop_name; - uint key_len; - ulong num_index; - zval *prop_copy; - - zend_hash_get_current_key_ex(ht_list[i], &key, &key_len, &num_index, 0, &pos); - zend_hash_move_forward_ex(ht_list[i], &pos); - zend_unmangle_property_name(key, key_len-1, &class_name, &prop_name); - if (class_name && class_name[0] != '*' && strcmp(class_name, ce->name)) { - /* filter privates from base classes */ - continue; - } - - /* copy: enforce read only access */ - ALLOC_ZVAL(prop_copy); - MAKE_COPY_ZVAL(prop, prop_copy); - - add_assoc_zval(return_value, prop_name, prop_copy); - } - } - } + add_class_vars(ce, 1, return_value TSRMLS_CC); + add_class_vars(ce, 0, return_value TSRMLS_CC); } /* }}} */ @@ -3308,7 +3565,7 @@ ZEND_METHOD(reflection_class, getFileName) } GET_REFLECTION_OBJECT_PTR(ce); if (ce->type == ZEND_USER_CLASS) { - RETURN_STRING(ce->filename, 1); + RETURN_STRING(ce->info.user.filename, 1); } RETURN_FALSE; } @@ -3326,7 +3583,7 @@ ZEND_METHOD(reflection_class, getStartLine) } GET_REFLECTION_OBJECT_PTR(ce); if (ce->type == ZEND_USER_FUNCTION) { - RETURN_LONG(ce->line_start); + RETURN_LONG(ce->info.user.line_start); } RETURN_FALSE; } @@ -3344,7 +3601,7 @@ ZEND_METHOD(reflection_class, getEndLine) } GET_REFLECTION_OBJECT_PTR(ce); if (ce->type == ZEND_USER_CLASS) { - RETURN_LONG(ce->line_end); + RETURN_LONG(ce->info.user.line_end); } RETURN_FALSE; } @@ -3361,8 +3618,8 @@ ZEND_METHOD(reflection_class, getDocComment) return; } GET_REFLECTION_OBJECT_PTR(ce); - if (ce->type == ZEND_USER_CLASS && ce->doc_comment) { - RETURN_STRINGL(ce->doc_comment, ce->doc_comment_len, 1); + if (ce->type == ZEND_USER_CLASS && ce->info.user.doc_comment) { + RETURN_STRINGL(ce->info.user.doc_comment, ce->info.user.doc_comment_len, 1); } RETURN_FALSE; } @@ -3394,7 +3651,7 @@ ZEND_METHOD(reflection_class, hasMethod) { reflection_object *intern; zend_class_entry *ce; - char *name, *lc_name; + char *name, *lc_name; int name_len; METHOD_NOTSTATIC(reflection_class_ptr); @@ -3424,7 +3681,7 @@ ZEND_METHOD(reflection_class, getMethod) zend_class_entry *ce; zend_function *mptr; zval obj_tmp; - char *name, *lc_name; + char *name, *lc_name; int name_len; METHOD_NOTSTATIC(reflection_class_ptr); @@ -3455,7 +3712,7 @@ ZEND_METHOD(reflection_class, getMethod) efree(lc_name); } else { efree(lc_name); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Method %s does not exist", name); return; } @@ -3493,7 +3750,7 @@ static int _addmethod_va(zend_function *mptr TSRMLS_DC zval *retval = va_arg(args, zval*); long filter = va_arg(args, long); zval *obj = va_arg(args, zval *); - + _addmethod(mptr, ce, retval, filter, obj TSRMLS_CC); return ZEND_HASH_APPLY_KEEP; } @@ -3539,7 +3796,7 @@ ZEND_METHOD(reflection_class, hasProperty) reflection_object *intern; zend_property_info *property_info; zend_class_entry *ce; - char *name; + char *name; int name_len; zval *property; @@ -3558,7 +3815,7 @@ ZEND_METHOD(reflection_class, hasProperty) if (intern->obj && Z_OBJ_HANDLER_P(intern->obj, has_property)) { MAKE_STD_ZVAL(property); ZVAL_STRINGL(property, name, name_len, 1); - if (Z_OBJ_HANDLER_P(intern->obj, has_property)(intern->obj, property, 2 TSRMLS_CC)) { + if (Z_OBJ_HANDLER_P(intern->obj, has_property)(intern->obj, property, 2, 0 TSRMLS_CC)) { zval_ptr_dtor(&property); RETURN_TRUE; } @@ -3576,7 +3833,7 @@ ZEND_METHOD(reflection_class, getProperty) reflection_object *intern; zend_class_entry *ce, **pce; zend_property_info *property_info; - char *name, *tmp, *classname; + char *name, *tmp, *classname; int name_len, classname_len; METHOD_NOTSTATIC(reflection_class_ptr); @@ -3632,9 +3889,9 @@ ZEND_METHOD(reflection_class, getProperty) if (zend_hash_find(&ce->properties_info, name, name_len + 1, (void**) &property_info) == SUCCESS && (property_info->flags & ZEND_ACC_SHADOW) == 0) { reflection_property_factory(ce, property_info, return_value TSRMLS_CC); return; - } + } } - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Property %s does not exist", name); } /* }}} */ @@ -3650,7 +3907,7 @@ static int _addproperty(zend_property_info *pptr TSRML if (pptr->flags & ZEND_ACC_SHADOW) { return 0; } - + if (pptr->flags & filter) { ALLOC_ZVAL(property); reflection_property_factory(ce, pptr, property TSRMLS_CC); @@ -3667,6 +3924,13 @@ static int _adddynproperty(zval **pptr TSRMLS_DC, int zend_class_entry *ce = *va_arg(args, zend_class_entry**); zval *retval = va_arg(args, zval*), member; + /* under some circumstances, the properties hash table may contain numeric + * properties (e.g. when casting from array). This is a WONT FIX bug, at + * least for the moment. Ignore these */ + if (hash_key->nKeyLength == 0) { + return 0; + } + if (hash_key->arKey[0] == '\0') { return 0; /* non public cannot be dynamic */ } @@ -3761,7 +4025,7 @@ ZEND_METHOD(reflection_class, getConstant) reflection_object *intern; zend_class_entry *ce; zval **value; - char *name; + char *name; int name_len; METHOD_NOTSTATIC(reflection_class_ptr); @@ -3817,6 +4081,39 @@ ZEND_METHOD(reflection_class, isInstantiable) } /* }}} */ +/* {{{ proto public bool ReflectionClass::isCloneable() + Returns whether this class is cloneable */ +ZEND_METHOD(reflection_class, isCloneable) +{ + reflection_object *intern; + zend_class_entry *ce; + zval obj; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ce); + if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS)) { + RETURN_FALSE; + } + if (intern->obj) { + if (ce->clone) { + RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC); + } else { + RETURN_BOOL(Z_OBJ_HANDLER_P(intern->obj, clone_obj) != NULL); + } + } else { + if (ce->clone) { + RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC); + } else { + object_init_ex(&obj, ce); + RETVAL_BOOL(Z_OBJ_HANDLER(obj, clone_obj) != NULL); + zval_dtor(&obj); + } + } +} +/* }}} */ + /* {{{ proto public bool ReflectionClass::isInterface() Returns whether this is an interface or a class */ ZEND_METHOD(reflection_class, isInterface) @@ -3825,6 +4122,14 @@ ZEND_METHOD(reflection_class, isInterface) } /* }}} */ +/* {{{ proto public bool ReflectionClass::isTrait() + Returns whether this is a trait */ +ZEND_METHOD(reflection_class, isTrait) +{ + _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_TRAIT & ~ZEND_ACC_EXPLICIT_ABSTRACT_CLASS); +} +/* }}} */ + /* {{{ proto public bool ReflectionClass::isFinal() Returns whether this class is final */ ZEND_METHOD(reflection_class, isFinal) @@ -3869,7 +4174,7 @@ ZEND_METHOD(reflection_class, isInstance) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { return; } - GET_REFLECTION_OBJECT_PTR(ce); + GET_REFLECTION_OBJECT_PTR(ce); RETURN_BOOL(HAS_CLASS_ENTRY(*object) && instanceof_function(Z_OBJCE_P(object), ce TSRMLS_CC)); } /* }}} */ @@ -3881,7 +4186,7 @@ ZEND_METHOD(reflection_class, newInstance) zval *retval_ptr = NULL; reflection_object *intern; zend_class_entry *ce; - + METHOD_NOTSTATIC(reflection_class_ptr); GET_REFLECTION_OBJECT_PTR(ce); @@ -3946,6 +4251,24 @@ ZEND_METHOD(reflection_class, newInstance) } /* }}} */ +/* {{{ proto public stdclass ReflectionClass::newInstanceWithoutConstructor() + Returns an instance of this class without invoking its constructor */ +ZEND_METHOD(reflection_class, newInstanceWithoutConstructor) +{ + reflection_object *intern; + zend_class_entry *ce; + + METHOD_NOTSTATIC(reflection_class_ptr); + GET_REFLECTION_OBJECT_PTR(ce); + + if (ce->create_object != NULL) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s is an internal class that cannot be instantiated without invoking its constructor", ce->name); + } + + object_init_ex(return_value, ce); +} +/* }}} */ + /* {{{ proto public stdclass ReflectionClass::newInstanceArgs([array args]) Returns an instance of this class */ ZEND_METHOD(reflection_class, newInstanceArgs) @@ -3955,8 +4278,8 @@ ZEND_METHOD(reflection_class, newInstanceArgs) zend_class_entry *ce; int argc = 0; HashTable *args; - - + + METHOD_NOTSTATIC(reflection_class_ptr); GET_REFLECTION_OBJECT_PTR(ce); @@ -3966,7 +4289,7 @@ ZEND_METHOD(reflection_class, newInstanceArgs) if (ZEND_NUM_ARGS() > 0) { argc = args->nNumOfElements; } - + /* Run the constructor if there is one */ if (ce->constructor) { zval ***params = NULL; @@ -3977,10 +4300,10 @@ ZEND_METHOD(reflection_class, newInstanceArgs) zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %s", ce->name); return; } - + if (argc) { params = safe_emalloc(sizeof(zval **), argc, 0); - zend_hash_apply_with_argument(args, (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC); + zend_hash_apply_with_argument(args, (apply_func_arg_t)_zval_array_to_c_array, ¶ms TSRMLS_CC); params -= argc; } @@ -4076,6 +4399,82 @@ ZEND_METHOD(reflection_class, getInterfaceNames) } /* }}} */ +/* {{{ proto public ReflectionClass[] ReflectionClass::getTraits() + Returns an array of traits used by this class */ +ZEND_METHOD(reflection_class, getTraits) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_uint i; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ce); + + array_init(return_value); + + for (i=0; i < ce->num_traits; i++) { + zval *trait; + ALLOC_ZVAL(trait); + zend_reflection_class_factory(ce->traits[i], trait TSRMLS_CC); + add_assoc_zval_ex(return_value, ce->traits[i]->name, ce->traits[i]->name_length + 1, trait); + } +} +/* }}} */ + +/* {{{ proto public String[] ReflectionClass::getTraitNames() + Returns an array of names of traits used by this class */ +ZEND_METHOD(reflection_class, getTraitNames) +{ + reflection_object *intern; + zend_class_entry *ce; + zend_uint i; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ce); + + array_init(return_value); + + for (i=0; i < ce->num_traits; i++) { + add_next_index_stringl(return_value, ce->traits[i]->name, ce->traits[i]->name_length, 1); + } +} +/* }}} */ + +/* {{{ proto public arra ReflectionClass::getTraitaliases() + Returns an array of trait aliases */ +ZEND_METHOD(reflection_class, getTraitAliases) +{ + reflection_object *intern; + zend_class_entry *ce; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(ce); + + array_init(return_value); + + if (ce->trait_aliases) { + zend_uint i = 0; + while (ce->trait_aliases[i]) { + char *method_name; + int method_name_len; + zend_trait_method_reference *cur_ref = ce->trait_aliases[i]->trait_method; + + if (ce->trait_aliases[i]->alias) { + method_name_len = spprintf(&method_name, 0, "%s::%s", cur_ref->ce->name, cur_ref->method_name); + add_assoc_stringl_ex(return_value, ce->trait_aliases[i]->alias, ce->trait_aliases[i]->alias_len + 1, method_name, method_name_len, 0); + } + i++; + } + } +} +/* }}} */ + /* {{{ proto public ReflectionClass ReflectionClass::getParentClass() Returns the class' parent class, or, if none exists, FALSE */ ZEND_METHOD(reflection_class, getParentClass) @@ -4087,7 +4486,7 @@ ZEND_METHOD(reflection_class, getParentClass) return; } GET_REFLECTION_OBJECT_PTR(ce); - + if (ce->parent) { zend_reflection_class_factory(ce->parent, return_value TSRMLS_CC); } else { @@ -4110,16 +4509,16 @@ ZEND_METHOD(reflection_class, isSubclassOf) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &class_name) == FAILURE) { return; } - + switch(class_name->type) { case IS_STRING: if (zend_lookup_class(Z_STRVAL_P(class_name), Z_STRLEN_P(class_name), &pce TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not exist", Z_STRVAL_P(class_name)); return; } class_ce = *pce; - break; + break; case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(class_name), reflection_class_ptr TSRMLS_CC)) { argument = (reflection_object *) zend_object_store_get_object(class_name TSRMLS_CC); @@ -4132,7 +4531,7 @@ ZEND_METHOD(reflection_class, isSubclassOf) } /* no break */ default: - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter one must either be a string or a ReflectionClass object"); return; } @@ -4155,16 +4554,16 @@ ZEND_METHOD(reflection_class, implementsInterface) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &interface) == FAILURE) { return; } - + switch(interface->type) { case IS_STRING: if (zend_lookup_class(Z_STRVAL_P(interface), Z_STRLEN_P(interface), &pce TSRMLS_CC) == FAILURE) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Interface %s does not exist", Z_STRVAL_P(interface)); return; } interface_ce = *pce; - break; + break; case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(interface), reflection_class_ptr TSRMLS_CC)) { argument = (reflection_object *) zend_object_store_get_object(interface TSRMLS_CC); @@ -4177,13 +4576,13 @@ ZEND_METHOD(reflection_class, implementsInterface) } /* no break */ default: - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter one must either be a string or a ReflectionClass object"); return; } if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Interface %s is a Class", interface_ce->name); return; } @@ -4197,7 +4596,7 @@ ZEND_METHOD(reflection_class, isIterateable) { reflection_object *intern; zend_class_entry *ce; - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -4215,7 +4614,7 @@ ZEND_METHOD(reflection_class, getExtension) { reflection_object *intern; zend_class_entry *ce; - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -4223,8 +4622,8 @@ ZEND_METHOD(reflection_class, getExtension) METHOD_NOTSTATIC(reflection_class_ptr); GET_REFLECTION_OBJECT_PTR(ce); - if (ce->module) { - reflection_extension_factory(return_value, ce->module->name TSRMLS_CC); + if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) { + reflection_extension_factory(return_value, ce->info.internal.module->name TSRMLS_CC); } } /* }}} */ @@ -4235,7 +4634,7 @@ ZEND_METHOD(reflection_class, getExtensionName) { reflection_object *intern; zend_class_entry *ce; - + if (zend_parse_parameters_none() == FAILURE) { return; } @@ -4243,8 +4642,8 @@ ZEND_METHOD(reflection_class, getExtensionName) METHOD_NOTSTATIC(reflection_class_ptr); GET_REFLECTION_OBJECT_PTR(ce); - if (ce->module) { - RETURN_STRING(ce->module->name, 1); + if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) { + RETURN_STRING(ce->info.internal.module->name, 1); } else { RETURN_FALSE; } @@ -4256,7 +4655,7 @@ ZEND_METHOD(reflection_class, getExtensionName) ZEND_METHOD(reflection_class, inNamespace) { zval **name; - char *colon; + const char *backslash; if (zend_parse_parameters_none() == FAILURE) { return; @@ -4265,8 +4664,8 @@ ZEND_METHOD(reflection_class, inNamespace) RETURN_FALSE; } if (Z_TYPE_PP(name) == IS_STRING - && (colon = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name))) - && colon > Z_STRVAL_PP(name)) + && (backslash = zend_memrchr(Z_STRVAL_PP(name), '\\', Z_STRLEN_PP(name))) + && backslash > Z_STRVAL_PP(name)) { RETURN_TRUE; } @@ -4279,7 +4678,7 @@ ZEND_METHOD(reflection_class, inNamespace) ZEND_METHOD(reflection_class, getNamespaceName) { zval **name; - char *backslash; + const char *backslash; if (zend_parse_parameters_none() == FAILURE) { return; @@ -4302,7 +4701,7 @@ ZEND_METHOD(reflection_class, getNamespaceName) ZEND_METHOD(reflection_class, getShortName) { zval **name; - char *backslash; + const char *backslash; if (zend_parse_parameters_none() == FAILURE) { return; @@ -4349,7 +4748,8 @@ ZEND_METHOD(reflection_property, export) ZEND_METHOD(reflection_property, __construct) { zval *propname, *classname; - char *name_str, *class_name, *prop_name; + char *name_str; + const char *class_name, *prop_name; int name_len, dynam_prop = 0; zval *object; reflection_object *intern; @@ -4367,13 +4767,13 @@ ZEND_METHOD(reflection_property, __construct) if (intern == NULL) { return; } - + /* Find the class entry */ switch (Z_TYPE_P(classname)) { case IS_STRING: if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &pce TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, - "Class %s does not exist", Z_STRVAL_P(classname)); + "Class %s does not exist", Z_STRVAL_P(classname)); return; } ce = *pce; @@ -4382,7 +4782,7 @@ ZEND_METHOD(reflection_property, __construct) case IS_OBJECT: ce = Z_OBJCE_P(classname); break; - + default: _DO_THROW("The parameter class is expected to be either a string or an object"); /* returns out of this function */ @@ -4400,12 +4800,12 @@ ZEND_METHOD(reflection_property, __construct) return; } } - + if (dynam_prop == 0 && (property_info->flags & ZEND_ACC_PRIVATE) == 0) { /* we have to search the class hierarchy for this (implicit) public or protected property */ zend_class_entry *tmp_ce = ce; zend_property_info *tmp_info; - + while (tmp_ce && zend_hash_find(&tmp_ce->properties_info, name_str, name_len + 1, (void **) &tmp_info) != SUCCESS) { ce = tmp_ce; property_info = tmp_info; @@ -4413,19 +4813,19 @@ ZEND_METHOD(reflection_property, __construct) } } - MAKE_STD_ZVAL(classname); + MAKE_STD_ZVAL(classname); MAKE_STD_ZVAL(propname); - + if (dynam_prop == 0) { zend_unmangle_property_name(property_info->name, property_info->name_length, &class_name, &prop_name); ZVAL_STRINGL(classname, property_info->ce->name, property_info->ce->name_length, 1); ZVAL_STRING(propname, prop_name, 1); } else { - ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); + ZVAL_STRINGL(classname, ce->name, ce->name_length, 1); ZVAL_STRINGL(propname, name_str, name_len, 1); } - zend_hash_update(Z_OBJPROP_P(object), "class", sizeof("class"), (void **) &classname, sizeof(zval *), NULL); - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &propname, sizeof(zval *), NULL); + reflection_update_property(object, "class", classname); + reflection_update_property(object, "name", propname); reference = (property_reference*) emalloc(sizeof(property_reference)); if (dynam_prop) { @@ -4475,7 +4875,7 @@ ZEND_METHOD(reflection_property, getName) } /* }}} */ -static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) +static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */ { reflection_object *intern; property_reference *ref; @@ -4486,6 +4886,7 @@ static void _property_check_flag(INTERNAL_FUNCTION_PAR GET_REFLECTION_OBJECT_PTR(ref); RETURN_BOOL(ref->prop.flags & mask); } +/* }}} */ /* {{{ proto public bool ReflectionProperty::isPublic() Returns whether this property is public */ @@ -4550,14 +4951,14 @@ ZEND_METHOD(reflection_property, getValue) reflection_object *intern; property_reference *ref; zval *object, name; - zval **member = NULL, *member_p = NULL; + zval *member_p = NULL; METHOD_NOTSTATIC(reflection_property_ptr); GET_REFLECTION_OBJECT_PTR(ref); if (!(ref->prop.flags & (ZEND_ACC_PUBLIC | ZEND_ACC_IMPLICIT_PUBLIC)) && intern->ignore_visibility == 0) { _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot access non-public member %s::%s", intern->ce->name, Z_STRVAL(name)); zval_dtor(&name); return; @@ -4565,14 +4966,16 @@ ZEND_METHOD(reflection_property, getValue) if ((ref->prop.flags & ZEND_ACC_STATIC)) { zend_update_class_constants(intern->ce TSRMLS_CC); - if (zend_hash_quick_find(CE_STATIC_MEMBERS(intern->ce), ref->prop.name, ref->prop.name_length + 1, ref->prop.h, (void **) &member) == FAILURE) { + if (!CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Could not find the property %s::%s", intern->ce->name, ref->prop.name); /* Bails out */ } - MAKE_COPY_ZVAL(member, return_value); + *return_value= *CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; + zval_copy_ctor(return_value); + INIT_PZVAL(return_value); } else { - char *class_name, *prop_name; - + const char *class_name, *prop_name; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { return; } @@ -4596,16 +4999,14 @@ ZEND_METHOD(reflection_property, setValue) zval **variable_ptr; zval *object, name; zval *value; - int setter_done = 0; zval *tmp; - HashTable *prop_table; METHOD_NOTSTATIC(reflection_property_ptr); GET_REFLECTION_OBJECT_PTR(ref); if (!(ref->prop.flags & ZEND_ACC_PUBLIC) && intern->ignore_visibility == 0) { _default_get_entry(getThis(), "name", sizeof("name"), &name TSRMLS_CC); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot access non-public member %s::%s", intern->ce->name, Z_STRVAL(name)); zval_dtor(&name); return; @@ -4618,36 +5019,37 @@ ZEND_METHOD(reflection_property, setValue) } } zend_update_class_constants(intern->ce TSRMLS_CC); - prop_table = CE_STATIC_MEMBERS(intern->ce); - if (zend_hash_quick_find(prop_table, ref->prop.name, ref->prop.name_length + 1, ref->prop.h, (void **) &variable_ptr) == FAILURE) { + if (!CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]) { php_error_docref(NULL TSRMLS_CC, E_ERROR, "Internal error: Could not find the property %s::%s", intern->ce->name, ref->prop.name); /* Bails out */ } - if (*variable_ptr == value) { - setter_done = 1; - } else { + variable_ptr = &CE_STATIC_MEMBERS(intern->ce)[ref->prop.offset]; + if (*variable_ptr != value) { if (PZVAL_IS_REF(*variable_ptr)) { - zval_dtor(*variable_ptr); - (*variable_ptr)->type = value->type; + zval garbage = **variable_ptr; /* old value should be destroyed */ + + /* To check: can't *variable_ptr be some system variable like error_zval here? */ + Z_TYPE_PP(variable_ptr) = Z_TYPE_P(value); (*variable_ptr)->value = value->value; if (Z_REFCOUNT_P(value) > 0) { zval_copy_ctor(*variable_ptr); } - setter_done = 1; - } - } - if (!setter_done) { - zval **foo; + zval_dtor(&garbage); + } else { + zval *garbage = *variable_ptr; - Z_ADDREF_P(value); - if (PZVAL_IS_REF(value)) { - SEPARATE_ZVAL(&value); + /* if we assign referenced variable, we should separate it */ + Z_ADDREF_P(value); + if (PZVAL_IS_REF(value)) { + SEPARATE_ZVAL(&value); + } + *variable_ptr = value; + zval_ptr_dtor(&garbage); } - zend_hash_quick_update(prop_table, ref->prop.name, ref->prop.name_length+1, ref->prop.h, &value, sizeof(zval *), (void **) &foo); } } else { - char *class_name, *prop_name; + const char *class_name, *prop_name; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) { return; @@ -4666,7 +5068,7 @@ ZEND_METHOD(reflection_property, getDeclaringClass) property_reference *ref; zend_class_entry *tmp_ce, *ce; zend_property_info *tmp_info; - char *prop_name, *class_name; + const char *prop_name, *class_name; int prop_name_len; if (zend_parse_parameters_none() == FAILURE) { @@ -4770,14 +5172,14 @@ ZEND_METHOD(reflection_extension, __construct) zend_str_tolower_copy(lcname, name_str, name_len); if (zend_hash_find(&module_registry, lcname, name_len + 1, (void **)&module) == FAILURE) { free_alloca(lcname, use_heap); - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Extension %s does not exist", name_str); return; } free_alloca(lcname, use_heap); MAKE_STD_ZVAL(name); ZVAL_STRING(name, module->name, 1); - zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); + reflection_update_property( object, "name", name); intern->ptr = module; intern->ref_type = REF_TYPE_OTHER; intern->ce = NULL; @@ -4835,7 +5237,7 @@ ZEND_METHOD(reflection_extension, getVersion) /* }}} */ /* {{{ proto public ReflectionFunction[] ReflectionExtension::getFunctions() - Returns an array of this extension's fuctions */ + Returns an array of this extension's functions */ ZEND_METHOD(reflection_extension, getFunctions) { reflection_object *intern; @@ -4863,7 +5265,7 @@ ZEND_METHOD(reflection_extension, getFunctions) efree(lc_name); continue; } - + ALLOC_ZVAL(function); reflection_function_factory(fptr, NULL, function TSRMLS_CC); add_assoc_zval_ex(return_value, func->fname, fname_len+1, function); @@ -4874,7 +5276,7 @@ ZEND_METHOD(reflection_extension, getFunctions) } /* }}} */ -static int _addconstant(zend_constant *constant TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) +static int _addconstant(zend_constant *constant TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { zval *const_val; zval *retval = va_arg(args, zval*); @@ -4889,6 +5291,7 @@ static int _addconstant(zend_constant *constant TSRMLS } return 0; } +/* }}} */ /* {{{ proto public array ReflectionExtension::getConstants() Returns an associative array containing this extension's constants and their values */ @@ -4948,7 +5351,7 @@ static int add_extension_class(zend_class_entry **pce struct _zend_module_entry *module = va_arg(args, struct _zend_module_entry*); int add_reflection_class = va_arg(args, int); - if ((*pce)->module && !strcasecmp((*pce)->module->name, module->name)) { + if (((*pce)->type == ZEND_INTERNAL_CLASS) && (*pce)->info.internal.module && !strcasecmp((*pce)->info.internal.module->name, module->name)) { if (add_reflection_class) { ALLOC_ZVAL(zclass); zend_reflection_class_factory(*pce, zclass TSRMLS_CC); @@ -5007,11 +5410,11 @@ ZEND_METHOD(reflection_extension, getDependencies) return; } GET_REFLECTION_OBJECT_PTR(module); - + array_init(return_value); dep = module->deps; - + if (!dep) { return; @@ -5021,7 +5424,7 @@ ZEND_METHOD(reflection_extension, getDependencies) char *relation; char *rel_type; int len; - + switch(dep->type) { case MODULE_DEP_REQUIRED: rel_type = "Required"; @@ -5037,10 +5440,10 @@ ZEND_METHOD(reflection_extension, getDependencies) break; } - len = spprintf(&relation, 0, "%s%s%s%s%s", + len = spprintf(&relation, 0, "%s%s%s%s%s", rel_type, dep->rel ? " " : "", - dep->rel ? dep->rel : "", + dep->rel ? dep->rel : "", dep->version ? " " : "", dep->version ? dep->version : ""); add_assoc_stringl(return_value, dep->name, relation, len, 0); @@ -5049,7 +5452,7 @@ ZEND_METHOD(reflection_extension, getDependencies) } /* }}} */ -/* {{{ proto public void ReflectionExtension::info() U +/* {{{ proto public void ReflectionExtension::info() Prints phpinfo block for the extension */ ZEND_METHOD(reflection_extension, info) { @@ -5065,6 +5468,180 @@ ZEND_METHOD(reflection_extension, info) } /* }}} */ +/* {{{ proto public bool ReflectionExtension::isPersistent() + Returns whether this extension is persistent */ +ZEND_METHOD(reflection_extension, isPersistent) +{ + reflection_object *intern; + zend_module_entry *module; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(module); + + RETURN_BOOL(module->type == MODULE_PERSISTENT); +} +/* }}} */ + +/* {{{ proto public bool ReflectionExtension::isTemporary() + Returns whether this extension is temporary */ +ZEND_METHOD(reflection_extension, isTemporary) +{ + reflection_object *intern; + zend_module_entry *module; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(module); + + RETURN_BOOL(module->type == MODULE_TEMPORARY); +} +/* }}} */ + +/* {{{ proto public static mixed ReflectionZendExtension::export(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_zend_extension, export) +{ + _reflection_export(INTERNAL_FUNCTION_PARAM_PASSTHRU, reflection_zend_extension_ptr, 1); +} +/* }}} */ + +/* {{{ proto public void ReflectionZendExtension::__construct(string name) + Constructor. Throws an Exception in case the given Zend extension does not exist */ +ZEND_METHOD(reflection_zend_extension, __construct) +{ + zval *name; + zval *object; + reflection_object *intern; + zend_extension *extension; + char *name_str; + int name_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == FAILURE) { + return; + } + + object = getThis(); + intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); + if (intern == NULL) { + return; + } + + extension = zend_get_extension(name_str); + if (!extension) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + "Zend Extension %s does not exist", name_str); + return; + } + MAKE_STD_ZVAL(name); + ZVAL_STRING(name, extension->name, 1); + reflection_update_property(object, "name", name); + intern->ptr = extension; + intern->ref_type = REF_TYPE_OTHER; + intern->ce = NULL; +} +/* }}} */ + +/* {{{ proto public string ReflectionZendExtension::__toString() + Returns a string representation */ +ZEND_METHOD(reflection_zend_extension, __toString) +{ + reflection_object *intern; + zend_extension *extension; + string str; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(extension); + string_init(&str); + _zend_extension_string(&str, extension, "" TSRMLS_CC); + RETURN_STRINGL(str.string, str.len - 1, 0); +} +/* }}} */ + +/* {{{ proto public string ReflectionZendExtension::getName() + Returns the name of this Zend extension */ +ZEND_METHOD(reflection_zend_extension, getName) +{ + reflection_object *intern; + zend_extension *extension; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(extension); + + RETURN_STRING(extension->name, 1); +} +/* }}} */ + +/* {{{ proto public string ReflectionZendExtension::getVersion() + Returns the version information of this Zend extension */ +ZEND_METHOD(reflection_zend_extension, getVersion) +{ + reflection_object *intern; + zend_extension *extension; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(extension); + + RETURN_STRING(extension->version ? extension->version : "", 1); +} +/* }}} */ + +/* {{{ proto public void ReflectionZendExtension::getAuthor() + * Returns the name of this Zend extension's author */ +ZEND_METHOD(reflection_zend_extension, getAuthor) +{ + reflection_object *intern; + zend_extension *extension; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(extension); + + RETURN_STRING(extension->author ? extension->author : "", 1); +} +/* }}} */ + +/* {{{ proto public void ReflectionZendExtension::getURL() + Returns this Zend extension's URL*/ +ZEND_METHOD(reflection_zend_extension, getURL) +{ + reflection_object *intern; + zend_extension *extension; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(extension); + + RETURN_STRING(extension->URL ? extension->URL : "", 1); +} +/* }}} */ + +/* {{{ proto public void ReflectionZendExtension::getCopyright() + Returns this Zend extension's copyright information */ +ZEND_METHOD(reflection_zend_extension, getCopyright) +{ + reflection_object *intern; + zend_extension *extension; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + GET_REFLECTION_OBJECT_PTR(extension); + + RETURN_STRING(extension->copyright ? extension->copyright : "", 1); +} +/* }}} */ + /* {{{ method tables */ static const zend_function_entry reflection_exception_functions[] = { PHP_FE_END @@ -5120,6 +5697,8 @@ static const zend_function_entry reflection_function_a ZEND_ME(reflection_function, isDeprecated, arginfo_reflection__void, 0) ZEND_ME(reflection_function, isInternal, arginfo_reflection__void, 0) ZEND_ME(reflection_function, isUserDefined, arginfo_reflection__void, 0) + ZEND_ME(reflection_function, getClosureThis, arginfo_reflection__void, 0) + ZEND_ME(reflection_function, getClosureScopeClass, arginfo_reflection__void, 0) ZEND_ME(reflection_function, getDocComment, arginfo_reflection__void, 0) ZEND_ME(reflection_function, getEndLine, arginfo_reflection__void, 0) ZEND_ME(reflection_function, getExtension, arginfo_reflection__void, 0) @@ -5144,6 +5723,7 @@ static const zend_function_entry reflection_function_f ZEND_ME(reflection_function, isDisabled, arginfo_reflection__void, 0) ZEND_ME(reflection_function, invoke, arginfo_reflection_function_invoke, 0) ZEND_ME(reflection_function, invokeArgs, arginfo_reflection_function_invokeArgs, 0) + ZEND_ME(reflection_function, getClosure, arginfo_reflection__void, 0) PHP_FE_END }; @@ -5172,6 +5752,10 @@ ZEND_BEGIN_ARG_INFO(arginfo_reflection_method_setAcces ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO(arginfo_reflection_method_getClosure, 0) + ZEND_ARG_INFO(0, object) +ZEND_END_ARG_INFO() + static const zend_function_entry reflection_method_functions[] = { ZEND_ME(reflection_method, export, arginfo_reflection_method_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) ZEND_ME(reflection_method, __construct, arginfo_reflection_method___construct, 0) @@ -5184,6 +5768,7 @@ static const zend_function_entry reflection_method_fun ZEND_ME(reflection_method, isStatic, arginfo_reflection__void, 0) ZEND_ME(reflection_method, isConstructor, arginfo_reflection__void, 0) ZEND_ME(reflection_method, isDestructor, arginfo_reflection__void, 0) + ZEND_ME(reflection_method, getClosure, arginfo_reflection_method_getClosure, 0) ZEND_ME(reflection_method, getModifiers, arginfo_reflection__void, 0) ZEND_ME(reflection_method, invoke, arginfo_reflection_method_invoke, 0) ZEND_ME(reflection_method, invokeArgs, arginfo_reflection_method_invokeArgs, 0) @@ -5253,6 +5838,9 @@ ZEND_BEGIN_ARG_INFO(arginfo_reflection_class_newInstan ZEND_ARG_INFO(0, args) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO(arginfo_reflection_class_newInstanceWithoutConstructor, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_class_newInstanceArgs, 0, 0, 0) ZEND_ARG_ARRAY_INFO(0, args, 0) ZEND_END_ARG_INFO() @@ -5274,6 +5862,7 @@ static const zend_function_entry reflection_class_func ZEND_ME(reflection_class, isInternal, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isUserDefined, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isInstantiable, arginfo_reflection__void, 0) + ZEND_ME(reflection_class, isCloneable, arginfo_reflection__void, 0) ZEND_ME(reflection_class, getFileName, arginfo_reflection__void, 0) ZEND_ME(reflection_class, getStartLine, arginfo_reflection__void, 0) ZEND_ME(reflection_class, getEndLine, arginfo_reflection__void, 0) @@ -5291,11 +5880,16 @@ static const zend_function_entry reflection_class_func ZEND_ME(reflection_class, getInterfaces, arginfo_reflection__void, 0) ZEND_ME(reflection_class, getInterfaceNames, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isInterface, arginfo_reflection__void, 0) + ZEND_ME(reflection_class, getTraits, arginfo_reflection__void, 0) + ZEND_ME(reflection_class, getTraitNames, arginfo_reflection__void, 0) + ZEND_ME(reflection_class, getTraitAliases, arginfo_reflection__void, 0) + ZEND_ME(reflection_class, isTrait, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isAbstract, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isFinal, arginfo_reflection__void, 0) ZEND_ME(reflection_class, getModifiers, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isInstance, arginfo_reflection_class_isInstance, 0) ZEND_ME(reflection_class, newInstance, arginfo_reflection_class_newInstance, 0) + ZEND_ME(reflection_class, newInstanceWithoutConstructor, arginfo_reflection_class_newInstanceWithoutConstructor, 0) ZEND_ME(reflection_class, newInstanceArgs, arginfo_reflection_class_newInstanceArgs, 0) ZEND_ME(reflection_class, getParentClass, arginfo_reflection__void, 0) ZEND_ME(reflection_class, isSubclassOf, arginfo_reflection_class_isSubclassOf, 0) @@ -5392,15 +5986,19 @@ static const zend_function_entry reflection_parameter_ ZEND_ME(reflection_parameter, __toString, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getName, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, isPassedByReference, arginfo_reflection__void, 0) + ZEND_ME(reflection_parameter, canBePassedByValue, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getDeclaringFunction, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getDeclaringClass, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getClass, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, isArray, arginfo_reflection__void, 0) + ZEND_ME(reflection_parameter, isCallable, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, allowsNull, arginfo_reflection__void, 0) ZEND_ME(reflection_parameter, getPosition, arginfo_reflection__void, 0) 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, isDefaultValueConstant, arginfo_reflection__void, 0) + ZEND_ME(reflection_parameter, getDefaultValueConstantName, arginfo_reflection__void, 0) PHP_FE_END }; @@ -5427,8 +6025,27 @@ static const zend_function_entry reflection_extension_ ZEND_ME(reflection_extension, getClassNames, arginfo_reflection__void, 0) ZEND_ME(reflection_extension, getDependencies, arginfo_reflection__void, 0) ZEND_ME(reflection_extension, info, arginfo_reflection__void, 0) + ZEND_ME(reflection_extension, isPersistent, arginfo_reflection__void, 0) + ZEND_ME(reflection_extension, isTemporary, arginfo_reflection__void, 0) PHP_FE_END }; + +ZEND_BEGIN_ARG_INFO(arginfo_reflection_zend_extension___construct, 0) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO() + +static const zend_function_entry reflection_zend_extension_functions[] = { + ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL) + ZEND_ME(reflection_zend_extension, export, arginfo_reflection_extension_export, ZEND_ACC_STATIC|ZEND_ACC_PUBLIC) + ZEND_ME(reflection_zend_extension, __construct, arginfo_reflection_extension___construct, 0) + ZEND_ME(reflection_zend_extension, __toString, arginfo_reflection__void, 0) + ZEND_ME(reflection_zend_extension, getName, arginfo_reflection__void, 0) + ZEND_ME(reflection_zend_extension, getVersion, arginfo_reflection__void, 0) + ZEND_ME(reflection_zend_extension, getAuthor, arginfo_reflection__void, 0) + ZEND_ME(reflection_zend_extension, getURL, arginfo_reflection__void, 0) + ZEND_ME(reflection_zend_extension, getCopyright, arginfo_reflection__void, 0) + PHP_FE_END +}; /* }}} */ const zend_function_entry reflection_ext_functions[] = { /* {{{ */ @@ -5438,19 +6055,19 @@ const zend_function_entry reflection_ext_functions[] = static zend_object_handlers *zend_std_obj_handlers; /* {{{ _reflection_write_property */ -static void _reflection_write_property(zval *object, zval *member, zval *value TSRMLS_DC) +static void _reflection_write_property(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC) { if ((Z_TYPE_P(member) == IS_STRING) - && zend_hash_exists(&Z_OBJCE_P(object)->default_properties, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) + && zend_hash_exists(&Z_OBJCE_P(object)->properties_info, Z_STRVAL_P(member), Z_STRLEN_P(member)+1) && ((Z_STRLEN_P(member) == sizeof("name") - 1 && !memcmp(Z_STRVAL_P(member), "name", sizeof("name"))) || (Z_STRLEN_P(member) == sizeof("class") - 1 && !memcmp(Z_STRVAL_P(member), "class", sizeof("class"))))) { - zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Cannot set read-only property %s::$%s", Z_OBJCE_P(object)->name, Z_STRVAL_P(member)); } else { - zend_std_obj_handlers->write_property(object, member, value TSRMLS_CC); + zend_std_obj_handlers->write_property(object, member, value, key TSRMLS_CC); } } /* }}} */ @@ -5537,6 +6154,12 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */ reflection_register_implement(reflection_extension_ptr, reflector_ptr TSRMLS_CC); zend_declare_property_string(reflection_extension_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC TSRMLS_CC); + INIT_CLASS_ENTRY(_reflection_entry, "ReflectionZendExtension", reflection_zend_extension_functions); + _reflection_entry.create_object = reflection_objects_new; + reflection_zend_extension_ptr = zend_register_internal_class(&_reflection_entry TSRMLS_CC); + 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); + return SUCCESS; } /* }}} */ @@ -5545,7 +6168,7 @@ PHP_MINFO_FUNCTION(reflection) /* {{{ */ php_info_print_table_start(); php_info_print_table_header(2, "Reflection", "enabled"); - php_info_print_table_row(2, "Version", "$Revision: 1.1.1.1 $"); + php_info_print_table_row(2, "Version", "$Id: php_reflection.c,v 1.1.1.4 2013/10/14 08:02:30 misho Exp $"); php_info_print_table_end(); } /* }}} */ @@ -5559,7 +6182,7 @@ zend_module_entry reflection_module_entry = { /* {{{ * NULL, NULL, PHP_MINFO(reflection), - "$Revision: 1.1.1.1 $", + "$Id: php_reflection.c,v 1.1.1.4 2013/10/14 08:02:30 misho Exp $", STANDARD_MODULE_PROPERTIES }; /* }}} */