From 2728e52d58545472c6a3e0ce2ad4797808f319f2 Mon Sep 17 00:00:00 2001 From: Marcus Boerger Date: Mon, 27 Sep 2004 19:01:50 +0000 Subject: [PATCH] MFH (discussed with Andi) --- Zend/zend_reflection_api.c | 257 ++++++++++++++++++++++++++------ ext/reflection/php_reflection.c | 257 ++++++++++++++++++++++++++------ 2 files changed, 428 insertions(+), 86 deletions(-) diff --git a/Zend/zend_reflection_api.c b/Zend/zend_reflection_api.c index eb8bf648be..0e72bac6fa 100644 --- a/Zend/zend_reflection_api.c +++ b/Zend/zend_reflection_api.c @@ -145,8 +145,10 @@ typedef struct _property_reference { /* Struct for parameters */ typedef struct _parameter_reference { - int offset; + zend_uint offset; + zend_uint required; struct _zend_arg_info *arg_info; + zend_function *fptr; } parameter_reference; /* Struct for reflection objects */ @@ -155,6 +157,7 @@ typedef struct { void *ptr; unsigned int free_ptr:1; zval *obj; + zend_class_entry *ce; } reflection_object; static zend_object_handlers reflection_object_handlers; @@ -501,9 +504,14 @@ static void _const_string(string *str, char *name, zval *value, char *indent TSR /* }}} */ /* {{{ _parameter_string */ -static void _parameter_string(string *str, struct _zend_arg_info *arg_info, int offset, char* indent TSRMLS_DC) +static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg_info *arg_info, zend_uint offset, zend_uint required, char* indent TSRMLS_DC) { string_printf(str, "Parameter #%d [ ", offset); + if (offset >= required) { + string_printf(str, " "); + } else { + string_printf(str, " "); + } if (arg_info->class_name) { string_printf(str, "%s ", arg_info->class_name); if (arg_info->allow_null) { @@ -518,6 +526,32 @@ static void _parameter_string(string *str, struct _zend_arg_info *arg_info, int } else { string_printf(str, "$param%d", offset); } + if (fptr->type == ZEND_USER_FUNCTION && offset >= required) { + zend_op *precv = &((zend_op_array*)fptr)->opcodes[offset*2 + 1]; + if (precv->opcode == ZEND_RECV_INIT && precv->op2.op_type != IS_UNUSED) { + zval *zv, zv_copy; + int use_copy; + string_write(str, " = ", sizeof(" = ")-1); + zv_copy = precv->op2.u.constant; + zv = &zv_copy; + zval_update_constant(&zv, (void*)1 TSRMLS_CC); + if (Z_TYPE_P(zv) == IS_NULL) { + string_write(str, "NULL", sizeof("NULL")-1); + } else if (Z_TYPE_P(zv) == IS_STRING) { + string_write(str, "'", sizeof("'")-1); + string_write(str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 15)); + if (Z_STRLEN_P(zv) > 15) { + string_write(str, "...", sizeof("...")-1); + } + string_write(str, "'", sizeof("'")-1); + } else { + zend_make_printable_zval(zv, &zv_copy, &use_copy); + string_write(str, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy)); + zval_dtor(&zv_copy); + } + zval_ptr_dtor(&zv); + } + } string_write(str, " ]", sizeof(" ]")-1); } /* }}} */ @@ -525,8 +559,8 @@ static void _parameter_string(string *str, struct _zend_arg_info *arg_info, int /* {{{ _function_parameter_string */ static void _function_parameter_string(string *str, zend_function *fptr, char* indent TSRMLS_DC) { - zend_uint i; struct _zend_arg_info *arg_info = fptr->common.arg_info; + zend_uint i, required = fptr->common.required_num_args; if (!arg_info) { return; @@ -536,7 +570,7 @@ static void _function_parameter_string(string *str, zend_function *fptr, char* i string_printf(str, "%s- Parameters [%d] {\n", indent, fptr->common.num_args); for (i = 0; i < fptr->common.num_args; i++) { string_printf(str, "%s ", indent); - _parameter_string(str, arg_info, i, indent TSRMLS_CC); + _parameter_string(str, fptr, arg_info, i, required, indent TSRMLS_CC); string_write(str, "\n", sizeof("\n")-1); arg_info++; } @@ -586,6 +620,9 @@ static void _function_string(string *str, zend_function *fptr, char* indent TSRM case ZEND_ACC_PROTECTED: string_printf(str, "protected "); break; + default: + string_printf(str, " "); + break; } string_printf(str, fptr->common.scope ? "method " : "function "); @@ -791,6 +828,7 @@ static void reflection_class_factory(zend_class_entry *ce, zval *object TSRMLS_D intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = ce; intern->free_ptr = 0; + intern->ce = ce; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ @@ -818,12 +856,13 @@ static void reflection_extension_factory(zval *object, char *name_str TSRMLS_DC) ZVAL_STRINGL(name, module->name, name_len, 1); intern->ptr = module; intern->free_ptr = 0; + intern->ce = NULL; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ /* {{{ reflection_parameter_factory */ -static void reflection_parameter_factory(struct _zend_arg_info *arg_info, int offset, zval *object TSRMLS_DC) +static void reflection_parameter_factory(zend_function *fptr, struct _zend_arg_info *arg_info, zend_uint offset, zend_uint required, zval *object TSRMLS_DC) { reflection_object *intern; parameter_reference *reference; @@ -840,8 +879,11 @@ static void reflection_parameter_factory(struct _zend_arg_info *arg_info, int of reference = (parameter_reference*) emalloc(sizeof(parameter_reference)); reference->arg_info = arg_info; reference->offset = offset; + reference->required = required; + reference->fptr = fptr; intern->ptr = reference; intern->free_ptr = 1; + intern->ce = fptr->common.scope; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ @@ -859,6 +901,7 @@ static void reflection_function_factory(zend_function *function, zval *object TS intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = function; intern->free_ptr = 0; + intern->ce = NULL; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ @@ -878,6 +921,7 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = method; intern->free_ptr = 0; + intern->ce = ce; 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); } @@ -923,6 +967,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info reference->prop = prop; intern->ptr = reference; intern->free_ptr = 1; + intern->ce = ce; 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); } @@ -1152,6 +1197,7 @@ ZEND_METHOD(reflection_function, __construct) zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = fptr; intern->free_ptr = 0; + intern->ce = NULL; } /* }}} */ @@ -1356,13 +1402,41 @@ ZEND_METHOD(reflection_function, returnsReference) } /* }}} */ -/* {{{ proto public ReflectionParameter[] ReflectionFunction::getParameters() +/* {{{ proto public bool ReflectionFunction::getNumberOfParameters() + Gets the number of required parameters */ +ZEND_METHOD(reflection_function, getNumberOfParameters) +{ + reflection_object *intern; + zend_function *fptr; + + METHOD_NOTSTATIC; + GET_REFLECTION_OBJECT_PTR(fptr); + + RETURN_LONG(fptr->common.num_args); +} +/* }}} */ + +/* {{{ proto public bool ReflectionFunction::getNumberOfRequiredParameters() + Gets the number of required parameters */ +ZEND_METHOD(reflection_function, getNumberOfRequiredParameters) +{ + reflection_object *intern; + zend_function *fptr; + + METHOD_NOTSTATIC; + GET_REFLECTION_OBJECT_PTR(fptr); + + RETURN_LONG(fptr->common.required_num_args); +} +/* }}} */ + +/* {{{ proto public ReflectionParameter[] Reflection_Function::getParameters() Returns an array of parameter objects for this function */ ZEND_METHOD(reflection_function, getParameters) { reflection_object *intern; zend_function *fptr; - int i; + zend_uint i; struct _zend_arg_info *arg_info; METHOD_NOTSTATIC; @@ -1375,7 +1449,7 @@ ZEND_METHOD(reflection_function, getParameters) zval *parameter; ALLOC_ZVAL(parameter); - reflection_parameter_factory(arg_info, i, parameter TSRMLS_CC); + reflection_parameter_factory(fptr, arg_info, i, fptr->common.required_num_args, parameter TSRMLS_CC); add_next_index_zval(return_value, parameter); arg_info++; @@ -1403,6 +1477,7 @@ ZEND_METHOD(reflection_parameter, __construct) zend_function *fptr; struct _zend_arg_info *arg_info; int position; + zend_class_entry *ce = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &reference, ¶meter) == FAILURE) { return; @@ -1435,7 +1510,6 @@ ZEND_METHOD(reflection_parameter, __construct) case IS_ARRAY: { zval **classref; zval **method; - zend_class_entry *ce; zend_class_entry **pce; char *lcname; @@ -1479,12 +1553,12 @@ ZEND_METHOD(reflection_parameter, __construct) arg_info = fptr->common.arg_info; if (Z_TYPE_P(parameter) == IS_LONG) { position= Z_LVAL_P(parameter); - if (position < 0 || position >= fptr->common.num_args) { + if (position < 0 || (zend_uint)position >= fptr->common.num_args) { _DO_THROW("The parameter specified by its offset could not be found"); /* returns out of this function */ } } else { - int i; + zend_uint i; position= -1; convert_to_string_ex(¶meter); @@ -1510,9 +1584,12 @@ ZEND_METHOD(reflection_parameter, __construct) ref = (parameter_reference*) emalloc(sizeof(parameter_reference)); ref->arg_info = &arg_info[position]; - ref->offset = position; + ref->offset = (zend_uint)position; + ref->required = fptr->common.required_num_args; + ref->fptr = fptr; intern->ptr = ref; intern->free_ptr = 1; + intern->ce = ce; } /* }}} */ @@ -1527,7 +1604,7 @@ ZEND_METHOD(reflection_parameter, __toString) METHOD_NOTSTATIC_NUMPARAMS(0); GET_REFLECTION_OBJECT_PTR(param); string_init(&str); - _parameter_string(&str, param->arg_info, param->offset, "" TSRMLS_CC); + _parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "" TSRMLS_CC); RETURN_STRINGL(str.string, str.len - 1, 0); } /* }}} */ @@ -1597,6 +1674,80 @@ ZEND_METHOD(reflection_parameter, isPassedByReference) } /* }}} */ +/* {{{ proto public bool ReflectionParameter::isOptional() + Returns whether this parameter is an optional parameter */ +ZEND_METHOD(reflection_parameter, isOptional) +{ + reflection_object *intern; + parameter_reference *param; + + METHOD_NOTSTATIC_NUMPARAMS(0); + GET_REFLECTION_OBJECT_PTR(param); + + RETVAL_BOOL(param->offset >= param->required); +} +/* }}} */ + +/* {{{ proto public bool ReflectionParameter::isDefaultValueAvailable() + Returns whether the default value of this parameter is available */ +ZEND_METHOD(reflection_parameter, isDefaultValueAvailable) +{ + reflection_object *intern; + parameter_reference *param; + zend_op *precv; + + METHOD_NOTSTATIC_NUMPARAMS(0); + GET_REFLECTION_OBJECT_PTR(param); + + if (param->fptr->type != ZEND_USER_FUNCTION) + { + RETURN_FALSE; + } + if (param->offset < param->required) { + RETURN_FALSE; + } + precv = &((zend_op_array*)param->fptr)->opcodes[param->offset*2 + 1]; + if (precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto public bool ReflectionParameter::getDefaultValue() + 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; + zval *zv, zv_copy; + + METHOD_NOTSTATIC_NUMPARAMS(0); + 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"); + return; + } + if (param->offset < param->required) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional"); + return; + } + precv = &((zend_op_array*)param->fptr)->opcodes[param->offset*2 + 1]; + if (precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error"); + return; + } + + zv_copy = precv->op2.u.constant; + zv = &zv_copy; + zval_update_constant(&zv, (void*)1 TSRMLS_CC); + RETURN_ZVAL(zv, 1, 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) @@ -1669,6 +1820,7 @@ ZEND_METHOD(reflection_method, __construct) zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = mptr; intern->free_ptr = 0; + intern->ce = ce; } /* }}} */ @@ -1848,7 +2000,10 @@ ZEND_METHOD(reflection_method, isConstructor) METHOD_NOTSTATIC_NUMPARAMS(0); GET_REFLECTION_OBJECT_PTR(mptr); - RETURN_BOOL(mptr->common.scope->constructor == mptr); + /* 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); } /* }}} */ @@ -1861,7 +2016,7 @@ ZEND_METHOD(reflection_method, isDestructor) METHOD_NOTSTATIC_NUMPARAMS(0); GET_REFLECTION_OBJECT_PTR(mptr); - RETURN_BOOL(mptr->common.scope->destructor == mptr); + RETURN_BOOL(mptr->common.fn_flags && ZEND_ACC_DTOR); } /* }}} */ @@ -2530,7 +2685,7 @@ ZEND_METHOD(reflection_class, getParentClass) } /* }}} */ -/* {{{ proto public bool ReflectionClass::isSubclassOf(string|reflection_class class) +/* {{{ proto public bool ReflectionClass::isSubclassOf(string|ReflectionClass class) Returns whether this class is a subclass of another class */ ZEND_METHOD(reflection_class, isSubclassOf) { @@ -2576,7 +2731,7 @@ ZEND_METHOD(reflection_class, isSubclassOf) } /* }}} */ -/* {{{ proto public bool ReflectionClass::implementsInterface(string|reflection_class interface_name) +/* {{{ proto public bool ReflectionClass::implementsInterface(string|ReflectionClass interface_name) Returns whether this class is a subclass of another class */ ZEND_METHOD(reflection_class, implementsInterface) { @@ -2777,6 +2932,7 @@ ZEND_METHOD(reflection_property, __construct) reference->prop = property_info; intern->ptr = reference; intern->free_ptr = 1; + intern->ce = ce; } /* }}} */ @@ -2869,7 +3025,7 @@ ZEND_METHOD(reflection_property, getModifiers) } /* }}} */ -/* {{{ proto public mixed ReflectionProperty::getValue(stdclass object) +/* {{{ proto public mixed ReflectionProperty::getValue([stdclass object]) Returns this property's value */ ZEND_METHOD(reflection_property, getValue) { @@ -2886,16 +3042,15 @@ ZEND_METHOD(reflection_property, getValue) /* Returns from this function */ } - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { - return; - } - if ((ref->prop->flags & ZEND_ACC_STATIC)) { - if (zend_hash_quick_find(Z_OBJCE_P(object)->static_members, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { + if (zend_hash_quick_find(intern->ce->static_members, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); /* Bails out */ } } else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { + return; + } if (zend_hash_quick_find(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); /* Bails out */ @@ -2907,7 +3062,7 @@ ZEND_METHOD(reflection_property, getValue) } /* }}} */ -/* {{{ proto public void ReflectionProperty::setValue(stdclass object, mixed value) +/* {{{ proto public void ReflectionProperty::setValue([stdclass object,] mixed value) Sets this property's value */ ZEND_METHOD(reflection_property, setValue) { @@ -2917,38 +3072,48 @@ ZEND_METHOD(reflection_property, setValue) zval *object; zval *value; int setter_done = 0; + zval *tmp; + HashTable *prop_table; METHOD_NOTSTATIC; GET_REFLECTION_OBJECT_PTR(ref); - if (ref->prop->flags & ~ZEND_ACC_PUBLIC) { + if (ref->prop->flags & ~(ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)) { _DO_THROW("Cannot access non-public member"); /* Returns from this function */ } - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) { - return; - } - - if (zend_hash_quick_find(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == SUCCESS) { - if (*variable_ptr == value) { - setter_done = 1; - } else { - if (PZVAL_IS_REF(*variable_ptr)) { - zval_dtor(*variable_ptr); - (*variable_ptr)->type = value->type; - (*variable_ptr)->value = value->value; - if (value->refcount > 0) { - zval_copy_ctor(*variable_ptr); - } - setter_done = 1; + if ((ref->prop->flags & ZEND_ACC_STATIC)) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &tmp, &value) == FAILURE) { + return; } } + prop_table = intern->ce->static_members; } else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) { + return; + } + prop_table = Z_OBJPROP_P(object); + } + + if (zend_hash_quick_find(prop_table, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == FAILURE) { zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); /* Bails out */ } - + if (*variable_ptr == value) { + setter_done = 1; + } else { + if (PZVAL_IS_REF(*variable_ptr)) { + zval_dtor(*variable_ptr); + (*variable_ptr)->type = value->type; + (*variable_ptr)->value = value->value; + if (value->refcount > 0) { + zval_copy_ctor(*variable_ptr); + } + setter_done = 1; + } + } if (!setter_done) { zval **foo; @@ -2956,7 +3121,7 @@ ZEND_METHOD(reflection_property, setValue) if (PZVAL_IS_REF(value)) { SEPARATE_ZVAL(&value); } - zend_hash_quick_update(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); + zend_hash_quick_update(prop_table, ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); } } /* }}} */ @@ -3017,6 +3182,7 @@ ZEND_METHOD(reflection_extension, __construct) zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = module; intern->free_ptr = 0; + intern->ce = NULL; } /* }}} */ @@ -3243,6 +3409,8 @@ static zend_function_entry reflection_function_functions[] = { ZEND_ME(reflection_function, invoke, NULL, 0) ZEND_ME(reflection_function, returnsReference, NULL, 0) ZEND_ME(reflection_function, getParameters, NULL, 0) + ZEND_ME(reflection_function, getNumberOfParameters, NULL, 0) + ZEND_ME(reflection_function, getNumberOfRequiredParameters, NULL, 0) {NULL, NULL, NULL} }; @@ -3335,6 +3503,9 @@ static zend_function_entry reflection_parameter_functions[] = { ZEND_ME(reflection_parameter, isPassedByReference, NULL, 0) ZEND_ME(reflection_parameter, getClass, NULL, 0) ZEND_ME(reflection_parameter, allowsNull, NULL, 0) + ZEND_ME(reflection_parameter, isOptional, NULL, 0) + ZEND_ME(reflection_parameter, isDefaultValueAvailable, NULL, 0) + ZEND_ME(reflection_parameter, getDefaultValue, NULL, 0) {NULL, NULL, NULL} }; diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index eb8bf648be..0e72bac6fa 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -145,8 +145,10 @@ typedef struct _property_reference { /* Struct for parameters */ typedef struct _parameter_reference { - int offset; + zend_uint offset; + zend_uint required; struct _zend_arg_info *arg_info; + zend_function *fptr; } parameter_reference; /* Struct for reflection objects */ @@ -155,6 +157,7 @@ typedef struct { void *ptr; unsigned int free_ptr:1; zval *obj; + zend_class_entry *ce; } reflection_object; static zend_object_handlers reflection_object_handlers; @@ -501,9 +504,14 @@ static void _const_string(string *str, char *name, zval *value, char *indent TSR /* }}} */ /* {{{ _parameter_string */ -static void _parameter_string(string *str, struct _zend_arg_info *arg_info, int offset, char* indent TSRMLS_DC) +static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg_info *arg_info, zend_uint offset, zend_uint required, char* indent TSRMLS_DC) { string_printf(str, "Parameter #%d [ ", offset); + if (offset >= required) { + string_printf(str, " "); + } else { + string_printf(str, " "); + } if (arg_info->class_name) { string_printf(str, "%s ", arg_info->class_name); if (arg_info->allow_null) { @@ -518,6 +526,32 @@ static void _parameter_string(string *str, struct _zend_arg_info *arg_info, int } else { string_printf(str, "$param%d", offset); } + if (fptr->type == ZEND_USER_FUNCTION && offset >= required) { + zend_op *precv = &((zend_op_array*)fptr)->opcodes[offset*2 + 1]; + if (precv->opcode == ZEND_RECV_INIT && precv->op2.op_type != IS_UNUSED) { + zval *zv, zv_copy; + int use_copy; + string_write(str, " = ", sizeof(" = ")-1); + zv_copy = precv->op2.u.constant; + zv = &zv_copy; + zval_update_constant(&zv, (void*)1 TSRMLS_CC); + if (Z_TYPE_P(zv) == IS_NULL) { + string_write(str, "NULL", sizeof("NULL")-1); + } else if (Z_TYPE_P(zv) == IS_STRING) { + string_write(str, "'", sizeof("'")-1); + string_write(str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 15)); + if (Z_STRLEN_P(zv) > 15) { + string_write(str, "...", sizeof("...")-1); + } + string_write(str, "'", sizeof("'")-1); + } else { + zend_make_printable_zval(zv, &zv_copy, &use_copy); + string_write(str, Z_STRVAL(zv_copy), Z_STRLEN(zv_copy)); + zval_dtor(&zv_copy); + } + zval_ptr_dtor(&zv); + } + } string_write(str, " ]", sizeof(" ]")-1); } /* }}} */ @@ -525,8 +559,8 @@ static void _parameter_string(string *str, struct _zend_arg_info *arg_info, int /* {{{ _function_parameter_string */ static void _function_parameter_string(string *str, zend_function *fptr, char* indent TSRMLS_DC) { - zend_uint i; struct _zend_arg_info *arg_info = fptr->common.arg_info; + zend_uint i, required = fptr->common.required_num_args; if (!arg_info) { return; @@ -536,7 +570,7 @@ static void _function_parameter_string(string *str, zend_function *fptr, char* i string_printf(str, "%s- Parameters [%d] {\n", indent, fptr->common.num_args); for (i = 0; i < fptr->common.num_args; i++) { string_printf(str, "%s ", indent); - _parameter_string(str, arg_info, i, indent TSRMLS_CC); + _parameter_string(str, fptr, arg_info, i, required, indent TSRMLS_CC); string_write(str, "\n", sizeof("\n")-1); arg_info++; } @@ -586,6 +620,9 @@ static void _function_string(string *str, zend_function *fptr, char* indent TSRM case ZEND_ACC_PROTECTED: string_printf(str, "protected "); break; + default: + string_printf(str, " "); + break; } string_printf(str, fptr->common.scope ? "method " : "function "); @@ -791,6 +828,7 @@ static void reflection_class_factory(zend_class_entry *ce, zval *object TSRMLS_D intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = ce; intern->free_ptr = 0; + intern->ce = ce; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ @@ -818,12 +856,13 @@ static void reflection_extension_factory(zval *object, char *name_str TSRMLS_DC) ZVAL_STRINGL(name, module->name, name_len, 1); intern->ptr = module; intern->free_ptr = 0; + intern->ce = NULL; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ /* {{{ reflection_parameter_factory */ -static void reflection_parameter_factory(struct _zend_arg_info *arg_info, int offset, zval *object TSRMLS_DC) +static void reflection_parameter_factory(zend_function *fptr, struct _zend_arg_info *arg_info, zend_uint offset, zend_uint required, zval *object TSRMLS_DC) { reflection_object *intern; parameter_reference *reference; @@ -840,8 +879,11 @@ static void reflection_parameter_factory(struct _zend_arg_info *arg_info, int of reference = (parameter_reference*) emalloc(sizeof(parameter_reference)); reference->arg_info = arg_info; reference->offset = offset; + reference->required = required; + reference->fptr = fptr; intern->ptr = reference; intern->free_ptr = 1; + intern->ce = fptr->common.scope; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ @@ -859,6 +901,7 @@ static void reflection_function_factory(zend_function *function, zval *object TS intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = function; intern->free_ptr = 0; + intern->ce = NULL; zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); } /* }}} */ @@ -878,6 +921,7 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC); intern->ptr = method; intern->free_ptr = 0; + intern->ce = ce; 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); } @@ -923,6 +967,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info reference->prop = prop; intern->ptr = reference; intern->free_ptr = 1; + intern->ce = ce; 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); } @@ -1152,6 +1197,7 @@ ZEND_METHOD(reflection_function, __construct) zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = fptr; intern->free_ptr = 0; + intern->ce = NULL; } /* }}} */ @@ -1356,13 +1402,41 @@ ZEND_METHOD(reflection_function, returnsReference) } /* }}} */ -/* {{{ proto public ReflectionParameter[] ReflectionFunction::getParameters() +/* {{{ proto public bool ReflectionFunction::getNumberOfParameters() + Gets the number of required parameters */ +ZEND_METHOD(reflection_function, getNumberOfParameters) +{ + reflection_object *intern; + zend_function *fptr; + + METHOD_NOTSTATIC; + GET_REFLECTION_OBJECT_PTR(fptr); + + RETURN_LONG(fptr->common.num_args); +} +/* }}} */ + +/* {{{ proto public bool ReflectionFunction::getNumberOfRequiredParameters() + Gets the number of required parameters */ +ZEND_METHOD(reflection_function, getNumberOfRequiredParameters) +{ + reflection_object *intern; + zend_function *fptr; + + METHOD_NOTSTATIC; + GET_REFLECTION_OBJECT_PTR(fptr); + + RETURN_LONG(fptr->common.required_num_args); +} +/* }}} */ + +/* {{{ proto public ReflectionParameter[] Reflection_Function::getParameters() Returns an array of parameter objects for this function */ ZEND_METHOD(reflection_function, getParameters) { reflection_object *intern; zend_function *fptr; - int i; + zend_uint i; struct _zend_arg_info *arg_info; METHOD_NOTSTATIC; @@ -1375,7 +1449,7 @@ ZEND_METHOD(reflection_function, getParameters) zval *parameter; ALLOC_ZVAL(parameter); - reflection_parameter_factory(arg_info, i, parameter TSRMLS_CC); + reflection_parameter_factory(fptr, arg_info, i, fptr->common.required_num_args, parameter TSRMLS_CC); add_next_index_zval(return_value, parameter); arg_info++; @@ -1403,6 +1477,7 @@ ZEND_METHOD(reflection_parameter, __construct) zend_function *fptr; struct _zend_arg_info *arg_info; int position; + zend_class_entry *ce = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &reference, ¶meter) == FAILURE) { return; @@ -1435,7 +1510,6 @@ ZEND_METHOD(reflection_parameter, __construct) case IS_ARRAY: { zval **classref; zval **method; - zend_class_entry *ce; zend_class_entry **pce; char *lcname; @@ -1479,12 +1553,12 @@ ZEND_METHOD(reflection_parameter, __construct) arg_info = fptr->common.arg_info; if (Z_TYPE_P(parameter) == IS_LONG) { position= Z_LVAL_P(parameter); - if (position < 0 || position >= fptr->common.num_args) { + if (position < 0 || (zend_uint)position >= fptr->common.num_args) { _DO_THROW("The parameter specified by its offset could not be found"); /* returns out of this function */ } } else { - int i; + zend_uint i; position= -1; convert_to_string_ex(¶meter); @@ -1510,9 +1584,12 @@ ZEND_METHOD(reflection_parameter, __construct) ref = (parameter_reference*) emalloc(sizeof(parameter_reference)); ref->arg_info = &arg_info[position]; - ref->offset = position; + ref->offset = (zend_uint)position; + ref->required = fptr->common.required_num_args; + ref->fptr = fptr; intern->ptr = ref; intern->free_ptr = 1; + intern->ce = ce; } /* }}} */ @@ -1527,7 +1604,7 @@ ZEND_METHOD(reflection_parameter, __toString) METHOD_NOTSTATIC_NUMPARAMS(0); GET_REFLECTION_OBJECT_PTR(param); string_init(&str); - _parameter_string(&str, param->arg_info, param->offset, "" TSRMLS_CC); + _parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "" TSRMLS_CC); RETURN_STRINGL(str.string, str.len - 1, 0); } /* }}} */ @@ -1597,6 +1674,80 @@ ZEND_METHOD(reflection_parameter, isPassedByReference) } /* }}} */ +/* {{{ proto public bool ReflectionParameter::isOptional() + Returns whether this parameter is an optional parameter */ +ZEND_METHOD(reflection_parameter, isOptional) +{ + reflection_object *intern; + parameter_reference *param; + + METHOD_NOTSTATIC_NUMPARAMS(0); + GET_REFLECTION_OBJECT_PTR(param); + + RETVAL_BOOL(param->offset >= param->required); +} +/* }}} */ + +/* {{{ proto public bool ReflectionParameter::isDefaultValueAvailable() + Returns whether the default value of this parameter is available */ +ZEND_METHOD(reflection_parameter, isDefaultValueAvailable) +{ + reflection_object *intern; + parameter_reference *param; + zend_op *precv; + + METHOD_NOTSTATIC_NUMPARAMS(0); + GET_REFLECTION_OBJECT_PTR(param); + + if (param->fptr->type != ZEND_USER_FUNCTION) + { + RETURN_FALSE; + } + if (param->offset < param->required) { + RETURN_FALSE; + } + precv = &((zend_op_array*)param->fptr)->opcodes[param->offset*2 + 1]; + if (precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto public bool ReflectionParameter::getDefaultValue() + 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; + zval *zv, zv_copy; + + METHOD_NOTSTATIC_NUMPARAMS(0); + 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"); + return; + } + if (param->offset < param->required) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Parameter is not optional"); + return; + } + precv = &((zend_op_array*)param->fptr)->opcodes[param->offset*2 + 1]; + if (precv->opcode != ZEND_RECV_INIT || precv->op2.op_type == IS_UNUSED) { + zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Internal error"); + return; + } + + zv_copy = precv->op2.u.constant; + zv = &zv_copy; + zval_update_constant(&zv, (void*)1 TSRMLS_CC); + RETURN_ZVAL(zv, 1, 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) @@ -1669,6 +1820,7 @@ ZEND_METHOD(reflection_method, __construct) zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = mptr; intern->free_ptr = 0; + intern->ce = ce; } /* }}} */ @@ -1848,7 +2000,10 @@ ZEND_METHOD(reflection_method, isConstructor) METHOD_NOTSTATIC_NUMPARAMS(0); GET_REFLECTION_OBJECT_PTR(mptr); - RETURN_BOOL(mptr->common.scope->constructor == mptr); + /* 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); } /* }}} */ @@ -1861,7 +2016,7 @@ ZEND_METHOD(reflection_method, isDestructor) METHOD_NOTSTATIC_NUMPARAMS(0); GET_REFLECTION_OBJECT_PTR(mptr); - RETURN_BOOL(mptr->common.scope->destructor == mptr); + RETURN_BOOL(mptr->common.fn_flags && ZEND_ACC_DTOR); } /* }}} */ @@ -2530,7 +2685,7 @@ ZEND_METHOD(reflection_class, getParentClass) } /* }}} */ -/* {{{ proto public bool ReflectionClass::isSubclassOf(string|reflection_class class) +/* {{{ proto public bool ReflectionClass::isSubclassOf(string|ReflectionClass class) Returns whether this class is a subclass of another class */ ZEND_METHOD(reflection_class, isSubclassOf) { @@ -2576,7 +2731,7 @@ ZEND_METHOD(reflection_class, isSubclassOf) } /* }}} */ -/* {{{ proto public bool ReflectionClass::implementsInterface(string|reflection_class interface_name) +/* {{{ proto public bool ReflectionClass::implementsInterface(string|ReflectionClass interface_name) Returns whether this class is a subclass of another class */ ZEND_METHOD(reflection_class, implementsInterface) { @@ -2777,6 +2932,7 @@ ZEND_METHOD(reflection_property, __construct) reference->prop = property_info; intern->ptr = reference; intern->free_ptr = 1; + intern->ce = ce; } /* }}} */ @@ -2869,7 +3025,7 @@ ZEND_METHOD(reflection_property, getModifiers) } /* }}} */ -/* {{{ proto public mixed ReflectionProperty::getValue(stdclass object) +/* {{{ proto public mixed ReflectionProperty::getValue([stdclass object]) Returns this property's value */ ZEND_METHOD(reflection_property, getValue) { @@ -2886,16 +3042,15 @@ ZEND_METHOD(reflection_property, getValue) /* Returns from this function */ } - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { - return; - } - if ((ref->prop->flags & ZEND_ACC_STATIC)) { - if (zend_hash_quick_find(Z_OBJCE_P(object)->static_members, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { + if (zend_hash_quick_find(intern->ce->static_members, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); /* Bails out */ } } else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "o", &object) == FAILURE) { + return; + } if (zend_hash_quick_find(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &member) == FAILURE) { zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); /* Bails out */ @@ -2907,7 +3062,7 @@ ZEND_METHOD(reflection_property, getValue) } /* }}} */ -/* {{{ proto public void ReflectionProperty::setValue(stdclass object, mixed value) +/* {{{ proto public void ReflectionProperty::setValue([stdclass object,] mixed value) Sets this property's value */ ZEND_METHOD(reflection_property, setValue) { @@ -2917,38 +3072,48 @@ ZEND_METHOD(reflection_property, setValue) zval *object; zval *value; int setter_done = 0; + zval *tmp; + HashTable *prop_table; METHOD_NOTSTATIC; GET_REFLECTION_OBJECT_PTR(ref); - if (ref->prop->flags & ~ZEND_ACC_PUBLIC) { + if (ref->prop->flags & ~(ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)) { _DO_THROW("Cannot access non-public member"); /* Returns from this function */ } - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) { - return; - } - - if (zend_hash_quick_find(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == SUCCESS) { - if (*variable_ptr == value) { - setter_done = 1; - } else { - if (PZVAL_IS_REF(*variable_ptr)) { - zval_dtor(*variable_ptr); - (*variable_ptr)->type = value->type; - (*variable_ptr)->value = value->value; - if (value->refcount > 0) { - zval_copy_ctor(*variable_ptr); - } - setter_done = 1; + if ((ref->prop->flags & ZEND_ACC_STATIC)) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &tmp, &value) == FAILURE) { + return; } } + prop_table = intern->ce->static_members; } else { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "oz", &object, &value) == FAILURE) { + return; + } + prop_table = Z_OBJPROP_P(object); + } + + if (zend_hash_quick_find(prop_table, ref->prop->name, ref->prop->name_length + 1, ref->prop->h, (void **) &variable_ptr) == FAILURE) { zend_error(E_ERROR, "Internal error: Could not find the property %s", ref->prop->name); /* Bails out */ } - + if (*variable_ptr == value) { + setter_done = 1; + } else { + if (PZVAL_IS_REF(*variable_ptr)) { + zval_dtor(*variable_ptr); + (*variable_ptr)->type = value->type; + (*variable_ptr)->value = value->value; + if (value->refcount > 0) { + zval_copy_ctor(*variable_ptr); + } + setter_done = 1; + } + } if (!setter_done) { zval **foo; @@ -2956,7 +3121,7 @@ ZEND_METHOD(reflection_property, setValue) if (PZVAL_IS_REF(value)) { SEPARATE_ZVAL(&value); } - zend_hash_quick_update(Z_OBJPROP_P(object), ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); + zend_hash_quick_update(prop_table, ref->prop->name, ref->prop->name_length+1, ref->prop->h, &value, sizeof(zval *), (void **) &foo); } } /* }}} */ @@ -3017,6 +3182,7 @@ ZEND_METHOD(reflection_extension, __construct) zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL); intern->ptr = module; intern->free_ptr = 0; + intern->ce = NULL; } /* }}} */ @@ -3243,6 +3409,8 @@ static zend_function_entry reflection_function_functions[] = { ZEND_ME(reflection_function, invoke, NULL, 0) ZEND_ME(reflection_function, returnsReference, NULL, 0) ZEND_ME(reflection_function, getParameters, NULL, 0) + ZEND_ME(reflection_function, getNumberOfParameters, NULL, 0) + ZEND_ME(reflection_function, getNumberOfRequiredParameters, NULL, 0) {NULL, NULL, NULL} }; @@ -3335,6 +3503,9 @@ static zend_function_entry reflection_parameter_functions[] = { ZEND_ME(reflection_parameter, isPassedByReference, NULL, 0) ZEND_ME(reflection_parameter, getClass, NULL, 0) ZEND_ME(reflection_parameter, allowsNull, NULL, 0) + ZEND_ME(reflection_parameter, isOptional, NULL, 0) + ZEND_ME(reflection_parameter, isDefaultValueAvailable, NULL, 0) + ZEND_ME(reflection_parameter, getDefaultValue, NULL, 0) {NULL, NULL, NULL} }; -- 2.40.0