/* 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 */
void *ptr;
unsigned int free_ptr:1;
zval *obj;
+ zend_class_entry *ce;
} reflection_object;
static zend_object_handlers reflection_object_handlers;
/* }}} */
/* {{{ _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, "<optional> ");
+ } else {
+ string_printf(str, "<required> ");
+ }
if (arg_info->class_name) {
string_printf(str, "%s ", arg_info->class_name);
if (arg_info->allow_null) {
} 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);
}
/* }}} */
/* {{{ _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;
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++;
}
case ZEND_ACC_PROTECTED:
string_printf(str, "protected ");
break;
+ default:
+ string_printf(str, "<visibilty error> ");
+ break;
}
string_printf(str, fptr->common.scope ? "method " : "function ");
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);
}
/* }}} */
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;
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);
}
/* }}} */
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);
}
/* }}} */
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);
}
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);
}
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;
}
/* }}} */
}
/* }}} */
-/* {{{ 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;
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++;
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;
case IS_ARRAY: {
zval **classref;
zval **method;
- zend_class_entry *ce;
zend_class_entry **pce;
char *lcname;
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);
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;
}
/* }}} */
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);
}
/* }}} */
}
/* }}} */
+/* {{{ 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)
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;
}
/* }}} */
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);
}
/* }}} */
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);
}
/* }}} */
}
/* }}} */
-/* {{{ 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)
{
}
/* }}} */
-/* {{{ 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)
{
reference->prop = property_info;
intern->ptr = reference;
intern->free_ptr = 1;
+ intern->ce = ce;
}
/* }}} */
}
/* }}} */
-/* {{{ proto public mixed ReflectionProperty::getValue(stdclass object)
+/* {{{ proto public mixed ReflectionProperty::getValue([stdclass object])
Returns this property's value */
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 */
}
/* }}} */
-/* {{{ 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)
{
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;
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);
}
}
/* }}} */
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;
}
/* }}} */
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}
};
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}
};
/* 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 */
void *ptr;
unsigned int free_ptr:1;
zval *obj;
+ zend_class_entry *ce;
} reflection_object;
static zend_object_handlers reflection_object_handlers;
/* }}} */
/* {{{ _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, "<optional> ");
+ } else {
+ string_printf(str, "<required> ");
+ }
if (arg_info->class_name) {
string_printf(str, "%s ", arg_info->class_name);
if (arg_info->allow_null) {
} 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);
}
/* }}} */
/* {{{ _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;
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++;
}
case ZEND_ACC_PROTECTED:
string_printf(str, "protected ");
break;
+ default:
+ string_printf(str, "<visibilty error> ");
+ break;
}
string_printf(str, fptr->common.scope ? "method " : "function ");
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);
}
/* }}} */
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;
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);
}
/* }}} */
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);
}
/* }}} */
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);
}
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);
}
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;
}
/* }}} */
}
/* }}} */
-/* {{{ 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;
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++;
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;
case IS_ARRAY: {
zval **classref;
zval **method;
- zend_class_entry *ce;
zend_class_entry **pce;
char *lcname;
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);
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;
}
/* }}} */
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);
}
/* }}} */
}
/* }}} */
+/* {{{ 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)
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;
}
/* }}} */
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);
}
/* }}} */
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);
}
/* }}} */
}
/* }}} */
-/* {{{ 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)
{
}
/* }}} */
-/* {{{ 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)
{
reference->prop = property_info;
intern->ptr = reference;
intern->free_ptr = 1;
+ intern->ce = ce;
}
/* }}} */
}
/* }}} */
-/* {{{ proto public mixed ReflectionProperty::getValue(stdclass object)
+/* {{{ proto public mixed ReflectionProperty::getValue([stdclass object])
Returns this property's value */
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 */
}
/* }}} */
-/* {{{ 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)
{
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;
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);
}
}
/* }}} */
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;
}
/* }}} */
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}
};
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}
};