mirror of
https://github.com/php/php-src.git
synced 2026-04-24 00:18:23 +02:00
- MFH Closure/Reflection integration (original idea by Christian Seiler)
This commit is contained in:
+140
-50
@@ -192,11 +192,18 @@ typedef struct _parameter_reference {
|
||||
zend_function *fptr;
|
||||
} parameter_reference;
|
||||
|
||||
typedef enum {
|
||||
REF_TYPE_OTHER, /* Must be 0 */
|
||||
REF_TYPE_FUNCTION,
|
||||
REF_TYPE_PARAMETER,
|
||||
REF_TYPE_PROPERTY,
|
||||
} reflection_type_t;
|
||||
|
||||
/* Struct for reflection objects */
|
||||
typedef struct {
|
||||
zend_object zo;
|
||||
void *ptr;
|
||||
unsigned int free_ptr:1;
|
||||
reflection_type_t ref_type;
|
||||
zval *obj;
|
||||
zend_class_entry *ce;
|
||||
} reflection_object;
|
||||
@@ -224,51 +231,59 @@ static void reflection_register_implement(zend_class_entry *class_entry, zend_cl
|
||||
class_entry->interfaces[num_interfaces - 1] = interface_entry;
|
||||
}
|
||||
|
||||
static void _free_function(zend_function *fptr TSRMLS_DC) /* {{{ */
|
||||
{
|
||||
if (fptr
|
||||
&& fptr->type == ZEND_INTERNAL_FUNCTION
|
||||
&& (fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) != 0
|
||||
) {
|
||||
efree(fptr->internal_function.function_name);
|
||||
efree(fptr);
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
static void reflection_free_objects_storage(void *object TSRMLS_DC)
|
||||
{
|
||||
reflection_object *intern = (reflection_object *) object;
|
||||
parameter_reference *reference;
|
||||
|
||||
if (intern->free_ptr && intern->ptr) {
|
||||
efree(intern->ptr);
|
||||
intern->ptr = NULL;
|
||||
if (intern->ptr) {
|
||||
switch (intern->ref_type) {
|
||||
case REF_TYPE_PARAMETER:
|
||||
reference = (parameter_reference*)intern->ptr;
|
||||
_free_function(reference->fptr TSRMLS_CC);
|
||||
efree(intern->ptr);
|
||||
break;
|
||||
case REF_TYPE_FUNCTION:
|
||||
_free_function(intern->ptr TSRMLS_CC);
|
||||
break;
|
||||
case REF_TYPE_PROPERTY:
|
||||
efree(intern->ptr);
|
||||
break;
|
||||
case REF_TYPE_OTHER:
|
||||
break;
|
||||
}
|
||||
}
|
||||
intern->ptr = NULL;
|
||||
if (intern->obj) {
|
||||
zval_ptr_dtor(&intern->obj);
|
||||
}
|
||||
zend_objects_free_object_storage(object TSRMLS_CC);
|
||||
}
|
||||
|
||||
static void reflection_objects_clone(void *object, void **object_clone TSRMLS_DC)
|
||||
{
|
||||
reflection_object *intern = (reflection_object *) object;
|
||||
reflection_object **intern_clone = (reflection_object **) object_clone;
|
||||
|
||||
*intern_clone = emalloc(sizeof(reflection_object));
|
||||
zend_object_std_init(&(*intern_clone)->zo, intern->zo.ce TSRMLS_CC);
|
||||
(*intern_clone)->ptr = intern->ptr;
|
||||
(*intern_clone)->free_ptr = intern->free_ptr;
|
||||
(*intern_clone)->obj = intern->obj;
|
||||
if (intern->obj) {
|
||||
zval_add_ref(&intern->obj);
|
||||
}
|
||||
}
|
||||
|
||||
static zend_object_value reflection_objects_new(zend_class_entry *class_type TSRMLS_DC)
|
||||
{
|
||||
zval tmp;
|
||||
zend_object_value retval;
|
||||
reflection_object *intern;
|
||||
|
||||
intern = emalloc(sizeof(reflection_object));
|
||||
intern = ecalloc(1, sizeof(reflection_object));
|
||||
intern->zo.ce = class_type;
|
||||
intern->zo.guards = NULL;
|
||||
intern->ptr = NULL;
|
||||
intern->obj = NULL;
|
||||
intern->free_ptr = 0;
|
||||
|
||||
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 *));
|
||||
retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, reflection_objects_clone TSRMLS_CC);
|
||||
retval.handle = zend_objects_store_put(intern, NULL, reflection_free_objects_storage, NULL TSRMLS_CC);
|
||||
retval.handlers = &reflection_object_handlers;
|
||||
return retval;
|
||||
}
|
||||
@@ -536,9 +551,20 @@ static void _class_string(string *str, zend_class_entry *ce, zval *obj, char *in
|
||||
zend_hash_get_current_key_ex(&ce->function_table, &key, &key_len, &num_index, 0, &pos) != HASH_KEY_IS_STRING ||
|
||||
zend_binary_strcasecmp(key, key_len-1, mptr->common.function_name, len) == 0) {
|
||||
|
||||
zend_function *closure;
|
||||
/* see if this is a closure */
|
||||
if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
|
||||
memcmp(mptr->common.function_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 &&
|
||||
(closure = zend_get_closure_invoke_method(obj TSRMLS_CC)) != NULL
|
||||
) {
|
||||
mptr = closure;
|
||||
} else {
|
||||
closure = NULL;
|
||||
}
|
||||
string_printf(&dyn, "\n");
|
||||
_function_string(&dyn, mptr, ce, sub_indent.string TSRMLS_CC);
|
||||
count++;
|
||||
_free_function(closure TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
zend_hash_move_forward_ex(&ce->function_table, &pos);
|
||||
@@ -1039,7 +1065,7 @@ PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object TSR
|
||||
reflection_instantiate(reflection_class_ptr, object TSRMLS_CC);
|
||||
intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
|
||||
intern->ptr = ce;
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_OTHER;
|
||||
intern->ce = ce;
|
||||
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
|
||||
}
|
||||
@@ -1068,7 +1094,7 @@ static void reflection_extension_factory(zval *object, const char *name_str TSRM
|
||||
MAKE_STD_ZVAL(name);
|
||||
ZVAL_STRINGL(name, module->name, name_len, 1);
|
||||
intern->ptr = module;
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_OTHER;
|
||||
intern->ce = NULL;
|
||||
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
|
||||
}
|
||||
@@ -1095,7 +1121,7 @@ static void reflection_parameter_factory(zend_function *fptr, struct _zend_arg_i
|
||||
reference->required = required;
|
||||
reference->fptr = fptr;
|
||||
intern->ptr = reference;
|
||||
intern->free_ptr = 1;
|
||||
intern->ref_type = REF_TYPE_PARAMETER;
|
||||
intern->ce = fptr->common.scope;
|
||||
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
|
||||
}
|
||||
@@ -1113,7 +1139,7 @@ static void reflection_function_factory(zend_function *function, zval *object TS
|
||||
reflection_instantiate(reflection_function_ptr, object TSRMLS_CC);
|
||||
intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
|
||||
intern->ptr = function;
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_FUNCTION;
|
||||
intern->ce = NULL;
|
||||
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
|
||||
}
|
||||
@@ -1133,7 +1159,7 @@ static void reflection_method_factory(zend_class_entry *ce, zend_function *metho
|
||||
reflection_instantiate(reflection_method_ptr, object TSRMLS_CC);
|
||||
intern = (reflection_object *) zend_object_store_get_object(object TSRMLS_CC);
|
||||
intern->ptr = method;
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_FUNCTION;
|
||||
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);
|
||||
@@ -1180,7 +1206,7 @@ static void reflection_property_factory(zend_class_entry *ce, zend_property_info
|
||||
reference->prop = *prop;
|
||||
reference->ignore_visibility = 0;
|
||||
intern->ptr = reference;
|
||||
intern->free_ptr = 1;
|
||||
intern->ref_type = REF_TYPE_PROPERTY;
|
||||
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);
|
||||
@@ -1411,7 +1437,7 @@ ZEND_METHOD(reflection_function, __construct)
|
||||
ZVAL_STRING(name, fptr->common.function_name, 1);
|
||||
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
|
||||
intern->ptr = fptr;
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_FUNCTION;
|
||||
intern->ce = NULL;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -1890,18 +1916,37 @@ ZEND_METHOD(reflection_parameter, __construct)
|
||||
convert_to_string_ex(method);
|
||||
lcname_len = Z_STRLEN_PP(method);
|
||||
lcname = zend_str_tolower_dup(Z_STRVAL_PP(method), lcname_len);
|
||||
if (zend_hash_find(&ce->function_table, lcname, lcname_len + 1, (void **) &fptr) == FAILURE) {
|
||||
if (ce == zend_ce_closure && Z_TYPE_PP(classref) == IS_OBJECT &&
|
||||
(lcname_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
|
||||
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 */
|
||||
} 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,
|
||||
"Method %s::%s() does not exist", Z_STRVAL_PP(classref), Z_TYPE_PP(method), Z_STRVAL_PP(method));
|
||||
"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_get_closure_invoke_method(reference TSRMLS_CC);
|
||||
} else if (zend_hash_find(&ce->function_table, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME), (void **)&fptr) == FAILURE) {
|
||||
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC,
|
||||
"Method %s::%s() does not exist", ce->name, ZEND_INVOKE_FUNC_NAME);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
_DO_THROW("The parameter class is expected to be either a string or an array(class, method)");
|
||||
_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 */
|
||||
}
|
||||
|
||||
@@ -1943,8 +1988,9 @@ ZEND_METHOD(reflection_parameter, __construct)
|
||||
ref->offset = (zend_uint)position;
|
||||
ref->required = fptr->common.required_num_args;
|
||||
ref->fptr = fptr;
|
||||
// TODO: copy fptr
|
||||
intern->ptr = ref;
|
||||
intern->free_ptr = 1;
|
||||
intern->ref_type = REF_TYPE_PARAMETER;
|
||||
intern->ce = ce;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -2207,7 +2253,7 @@ ZEND_METHOD(reflection_method, export)
|
||||
ZEND_METHOD(reflection_method, __construct)
|
||||
{
|
||||
zval *name, *classname;
|
||||
zval *object;
|
||||
zval *object, *orig_obj;
|
||||
reflection_object *intern;
|
||||
char *lcname;
|
||||
zend_class_entry **pce;
|
||||
@@ -2217,7 +2263,11 @@ ZEND_METHOD(reflection_method, __construct)
|
||||
int name_len, tmp_len;
|
||||
zval ztmp;
|
||||
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "zs", &classname, &name_str, &name_len) == FAILURE) {
|
||||
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "o", &classname) == SUCCESS) {
|
||||
name_str = ZEND_INVOKE_FUNC_NAME;
|
||||
name_len = sizeof(ZEND_INVOKE_FUNC_NAME)-1;
|
||||
orig_obj = classname;
|
||||
} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "zs", &classname, &name_str, &name_len) == FAILURE) {
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name_str, &name_len) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
@@ -2230,6 +2280,11 @@ ZEND_METHOD(reflection_method, __construct)
|
||||
ZVAL_STRINGL(classname, name_str, tmp_len, 1);
|
||||
name_len = name_len - (tmp_len + 2);
|
||||
name_str = tmp + 2;
|
||||
orig_obj = NULL;
|
||||
} else if (Z_TYPE_P(classname) == IS_OBJECT) {
|
||||
orig_obj = classname;
|
||||
} else {
|
||||
orig_obj = NULL;
|
||||
}
|
||||
|
||||
object = getThis();
|
||||
@@ -2275,7 +2330,12 @@ ZEND_METHOD(reflection_method, __construct)
|
||||
|
||||
lcname = zend_str_tolower_dup(name_str, name_len);
|
||||
|
||||
if (zend_hash_find(&ce->function_table, lcname, name_len + 1, (void **) &mptr) == FAILURE) {
|
||||
if (ce == zend_ce_closure && orig_obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
|
||||
memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 &&
|
||||
(mptr = zend_get_closure_invoke_method(orig_obj TSRMLS_CC)) != NULL
|
||||
) {
|
||||
/* 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,
|
||||
"Method %s::%s() does not exist", ce->name, name_str);
|
||||
@@ -2287,7 +2347,7 @@ ZEND_METHOD(reflection_method, __construct)
|
||||
ZVAL_STRING(name, mptr->common.function_name, 1);
|
||||
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
|
||||
intern->ptr = mptr;
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_FUNCTION;
|
||||
intern->ce = ce;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -2792,7 +2852,7 @@ static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, int is_ob
|
||||
|
||||
intern->ptr = *ce;
|
||||
}
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_OTHER;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -3139,7 +3199,13 @@ ZEND_METHOD(reflection_class, getMethod)
|
||||
|
||||
GET_REFLECTION_OBJECT_PTR(ce);
|
||||
lc_name = zend_str_tolower_dup(name, name_len);
|
||||
if (zend_hash_find(&ce->function_table, lc_name, name_len + 1, (void**) &mptr) == SUCCESS) {
|
||||
if (ce == zend_ce_closure && intern->obj && (name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
|
||||
memcmp(lc_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 &&
|
||||
(mptr = zend_get_closure_invoke_method(intern->obj TSRMLS_CC)) != NULL
|
||||
) {
|
||||
reflection_method_factory(ce, mptr, return_value TSRMLS_CC);
|
||||
efree(lc_name);
|
||||
} else if (zend_hash_find(&ce->function_table, lc_name, name_len + 1, (void**) &mptr) == SUCCESS) {
|
||||
reflection_method_factory(ce, mptr, return_value TSRMLS_CC);
|
||||
efree(lc_name);
|
||||
} else {
|
||||
@@ -3152,19 +3218,36 @@ ZEND_METHOD(reflection_class, getMethod)
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _addmethod */
|
||||
static int _addmethod(zend_function *mptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
|
||||
static void _addmethod(zend_function *mptr, zend_class_entry *ce, zval *retval, long filter, zval *obj TSRMLS_DC)
|
||||
{
|
||||
zval *method;
|
||||
zend_class_entry *ce = *va_arg(args, zend_class_entry**);
|
||||
zval *retval = va_arg(args, zval*);
|
||||
long filter = va_arg(args, long);
|
||||
uint len = strlen(mptr->common.function_name);
|
||||
zend_function *closure;
|
||||
|
||||
if (mptr->common.fn_flags & filter) {
|
||||
ALLOC_ZVAL(method);
|
||||
if (ce == zend_ce_closure && obj && (len == sizeof(ZEND_INVOKE_FUNC_NAME)-1) &&
|
||||
memcmp(mptr->common.function_name, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0 &&
|
||||
(closure = zend_get_closure_invoke_method(obj TSRMLS_CC)) != NULL
|
||||
) {
|
||||
mptr = closure;
|
||||
}
|
||||
reflection_method_factory(ce, mptr, method TSRMLS_CC);
|
||||
add_next_index_zval(retval, method);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ _addmethod */
|
||||
static int _addmethod_va(zend_function *mptr TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key)
|
||||
{
|
||||
zend_class_entry *ce = *va_arg(args, zend_class_entry**);
|
||||
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;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -3190,7 +3273,14 @@ ZEND_METHOD(reflection_class, getMethods)
|
||||
GET_REFLECTION_OBJECT_PTR(ce);
|
||||
|
||||
array_init(return_value);
|
||||
zend_hash_apply_with_arguments(&ce->function_table TSRMLS_CC, (apply_func_args_t) _addmethod, 3, &ce, return_value, filter);
|
||||
zend_hash_apply_with_arguments(&ce->function_table TSRMLS_CC, (apply_func_args_t) _addmethod_va, 4, &ce, return_value, filter, intern->obj);
|
||||
if (intern->obj && instanceof_function(ce, zend_ce_closure)) {
|
||||
zend_function *closure = zend_get_closure_invoke_method(intern->obj TSRMLS_CC);
|
||||
if (closure) {
|
||||
_addmethod(closure, ce, return_value, filter, intern->obj TSRMLS_CC);
|
||||
_free_function(closure TSRMLS_CC);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -4027,7 +4117,7 @@ ZEND_METHOD(reflection_property, __construct)
|
||||
reference->prop = *property_info;
|
||||
reference->ignore_visibility = 0;
|
||||
intern->ptr = reference;
|
||||
intern->free_ptr = 1;
|
||||
intern->ref_type = REF_TYPE_PROPERTY;
|
||||
intern->ce = ce;
|
||||
}
|
||||
/* }}} */
|
||||
@@ -4347,7 +4437,7 @@ ZEND_METHOD(reflection_extension, __construct)
|
||||
ZVAL_STRING(name, module->name, 1);
|
||||
zend_hash_update(Z_OBJPROP_P(object), "name", sizeof("name"), (void **) &name, sizeof(zval *), NULL);
|
||||
intern->ptr = module;
|
||||
intern->free_ptr = 0;
|
||||
intern->ref_type = REF_TYPE_OTHER;
|
||||
intern->ce = NULL;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
--TEST--
|
||||
Reflection on closures
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
$closure = function($a, $b = 0) { };
|
||||
|
||||
$ro = new ReflectionObject($closure);
|
||||
$rm = $ro->getMethod('__invoke');
|
||||
var_dump($rm->getNumberOfParameters());
|
||||
var_dump($rm->getNumberOfRequiredParameters());
|
||||
$rms = $ro->getMethods();
|
||||
foreach($rms as $rm) {
|
||||
if ($rm->getName() == '__invoke') {
|
||||
var_dump($rm->getNumberOfParameters());
|
||||
var_dump($rm->getNumberOfRequiredParameters());
|
||||
}
|
||||
}
|
||||
|
||||
echo "---\n";
|
||||
|
||||
$rm = new ReflectionMethod($closure);
|
||||
var_dump($rm->getName());
|
||||
var_dump($rm->getNumberOfParameters());
|
||||
var_dump($rm->getNumberOfRequiredParameters());
|
||||
|
||||
echo "---\n";
|
||||
|
||||
$rp = new ReflectionParameter(array($closure, '__invoke'), 0);
|
||||
var_dump($rp->isOptional());
|
||||
$rp = new ReflectionParameter(array($closure, '__invoke'), 1);
|
||||
var_dump($rp->isOptional());
|
||||
$rp = new ReflectionParameter(array($closure, '__invoke'), 'a');
|
||||
var_dump($rp->isOptional());
|
||||
$rp = new ReflectionParameter(array($closure, '__invoke'), 'b');
|
||||
var_dump($rp->isOptional());
|
||||
|
||||
echo "---\n";
|
||||
|
||||
$rp = new ReflectionParameter($closure, 0);
|
||||
var_dump($rp->isOptional());
|
||||
$rp = new ReflectionParameter($closure, 1);
|
||||
var_dump($rp->isOptional());
|
||||
$rp = new ReflectionParameter($closure, 'a');
|
||||
var_dump($rp->isOptional());
|
||||
$rp = new ReflectionParameter($closure, 'b');
|
||||
var_dump($rp->isOptional());
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
int(2)
|
||||
int(1)
|
||||
int(2)
|
||||
int(1)
|
||||
---
|
||||
string(8) "__invoke"
|
||||
int(2)
|
||||
int(1)
|
||||
---
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
---
|
||||
bool(false)
|
||||
bool(true)
|
||||
bool(false)
|
||||
bool(true)
|
||||
===DONE===
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
--TEST--
|
||||
Reflection on invokable objects
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class Test {
|
||||
function __invoke($a, $b = 0) { }
|
||||
}
|
||||
|
||||
$rm = new ReflectionMethod(new Test);
|
||||
var_dump($rm->getName());
|
||||
var_dump($rm->getNumberOfParameters());
|
||||
var_dump($rm->getNumberOfRequiredParameters());
|
||||
|
||||
$rp = new ReflectionParameter(new Test, 0);
|
||||
var_dump($rp->isOptional());
|
||||
|
||||
$rp = new ReflectionParameter(new Test, 1);
|
||||
var_dump($rp->isOptional());
|
||||
|
||||
?>
|
||||
===DONE===
|
||||
--EXPECTF--
|
||||
string(8) "__invoke"
|
||||
int(2)
|
||||
int(1)
|
||||
bool(false)
|
||||
bool(true)
|
||||
===DONE===
|
||||
@@ -9,15 +9,23 @@ function ReflectionParameterTest($test, $test2 = null) {
|
||||
}
|
||||
$reflect = new ReflectionFunction('ReflectionParameterTest');
|
||||
$params = $reflect->getParameters();
|
||||
foreach($params as $key => $value) {
|
||||
ReflectionParameter::export($reflect, $key);
|
||||
try {
|
||||
foreach($params as $key => $value) {
|
||||
ReflectionParameter::export($reflect, $key);
|
||||
}
|
||||
}
|
||||
catch (ReflectionException $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
try {
|
||||
foreach($params as $key => $value) {
|
||||
ReflectionParameter::export(42, $key);
|
||||
}
|
||||
}
|
||||
catch (ReflectionException $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
|
||||
Fatal error: Uncaught exception 'ReflectionException' with message 'The parameter class is expected to be either a string or an array(class, method)' in %s.php:%d
|
||||
Stack trace:
|
||||
#0 [internal function]: ReflectionParameter->__construct(Object(ReflectionFunction), 0)
|
||||
#1 %s.php(%d): ReflectionParameter::export(Object(ReflectionFunction), 0)
|
||||
#2 {main}
|
||||
thrown in %s.php on line %d
|
||||
Method ReflectionFunction::__invoke() does not exist
|
||||
The parameter class is expected to be either a string, an array(class, method) or a callable object
|
||||
|
||||
Reference in New Issue
Block a user