}
/* }}} */
+static zend_function *_copy_function(zend_function *fptr TSRMLS_DC) /* {{{ */
+{
+ if (fptr
+ && fptr->type == ZEND_INTERNAL_FUNCTION
+ && (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0)
+ {
+ zend_function *copy_fptr;
+ copy_fptr = emalloc(sizeof(zend_function));
+ memcpy(copy_fptr, fptr, sizeof(zend_function));
+ if (UG(unicode)) {
+ copy_fptr->internal_function.function_name.u = eustrdup(fptr->internal_function.function_name.u);
+ } else {
+ copy_fptr->internal_function.function_name.s = estrdup(fptr->internal_function.function_name.s);
+ }
+ return copy_fptr;
+ } else {
+ /* no copy needed */
+ return fptr;
+ }
+}
+/* }}} */
+
static void _free_function(zend_function *fptr TSRMLS_DC) /* {{{ */
{
if (fptr
zval *parameter;
ALLOC_ZVAL(parameter);
- reflection_parameter_factory(fptr, arg_info, i, fptr->common.required_num_args, parameter TSRMLS_CC);
+ reflection_parameter_factory(_copy_function(fptr TSRMLS_CC), arg_info, i, fptr->common.required_num_args, parameter TSRMLS_CC);
add_next_index_zval(return_value, parameter);
arg_info++;
} else if (zend_u_hash_find(&ce->function_table, Z_TYPE_PP(method), lcname, lcname_len + 1, (void **) &fptr) == FAILURE) {
efree(lcname.v);
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
- "Method %R::%R() does not exist", Z_TYPE_PP(classref), Z_UNIVAL_PP(classref), Z_TYPE_PP(method), Z_UNIVAL_PP(method));
+ "Method %v::%R() does not exist", ce->name, Z_TYPE_PP(method), Z_UNIVAL_PP(method));
return;
}
efree(lcname.v);
GET_REFLECTION_OBJECT_PTR(param);
if (!param->fptr->common.scope) {
- reflection_function_factory(param->fptr, return_value TSRMLS_CC);
+ reflection_function_factory(_copy_function(param->fptr TSRMLS_CC), return_value TSRMLS_CC);
} else {
- reflection_method_factory(param->fptr->common.scope, param->fptr, return_value TSRMLS_CC);
+ reflection_method_factory(param->fptr->common.scope, _copy_function(param->fptr TSRMLS_CC), return_value TSRMLS_CC);
}
}
/* }}} */
/* Returns from this function */
}
- zend_create_closure(return_value, mptr, mptr->common.scope, obj TSRMLS_CC);
+ /* 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);
+ }
}
}
/* }}} */
--- /dev/null
+--TEST--
+Reflection on closures: Segfaults with getParameters() and getDeclaringFunction()
+--FILE--
+<?php
+
+$closure = function($a, $b = 0) { };
+
+$method = new ReflectionMethod ($closure);
+$params = $method->getParameters ();
+unset ($method);
+$method = $params[0]->getDeclaringFunction ();
+unset ($params);
+echo $method->getName ()."\n";
+
+$parameter = new ReflectionParameter ($closure, 'b');
+$method = $parameter->getDeclaringFunction ();
+unset ($parameter);
+echo $method->getName ()."\n";
+
+?>
+===DONE===
+--EXPECTF--
+__invoke
+__invoke
+===DONE===
--- /dev/null
+--TEST--
+ReflectionParameter::__construct(): Invalid method as constructor
+--FILE--
+<?php
+
+// Invalid class name
+try {
+ new ReflectionParameter (array ('A', 'b'), 0);
+} catch (ReflectionException $e) { echo $e->getMessage ()."\n"; }
+
+// Invalid class method
+try {
+ new ReflectionParameter (array ('C', 'b'), 0);
+} catch (ReflectionException $e) { echo $e->getMessage ()."\n"; }
+
+// Invalid object method
+try {
+ new ReflectionParameter (array (new C, 'b'), 0);
+} catch (ReflectionException $e) { echo $e->getMessage ()."\n"; }
+
+echo "Done.\n";
+
+class C {
+}
+
+?>
+--EXPECTF--
+Class A does not exist
+Method C::b() does not exist
+Method C::b() does not exist
+Done.