summaryrefslogtreecommitdiff
path: root/ext/reflection/php_reflection.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/reflection/php_reflection.c')
-rw-r--r--ext/reflection/php_reflection.c210
1 files changed, 202 insertions, 8 deletions
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 92f67972d2..4c570d7573 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -59,6 +59,7 @@ PHPAPI zend_class_entry *reflection_function_abstract_ptr;
PHPAPI zend_class_entry *reflection_function_ptr;
PHPAPI zend_class_entry *reflection_generator_ptr;
PHPAPI zend_class_entry *reflection_parameter_ptr;
+PHPAPI zend_class_entry *reflection_type_ptr;
PHPAPI zend_class_entry *reflection_class_ptr;
PHPAPI zend_class_entry *reflection_object_ptr;
PHPAPI zend_class_entry *reflection_method_ptr;
@@ -201,11 +202,18 @@ typedef struct _parameter_reference {
zend_function *fptr;
} parameter_reference;
+/* Struct for type hints */
+typedef struct _type_reference {
+ struct _zend_arg_info *arg_info;
+ zend_function *fptr;
+} type_reference;
+
typedef enum {
REF_TYPE_OTHER, /* Must be 0 */
REF_TYPE_FUNCTION,
REF_TYPE_GENERATOR,
REF_TYPE_PARAMETER,
+ REF_TYPE_TYPE,
REF_TYPE_PROPERTY,
REF_TYPE_DYNAMIC_PROPERTY
} reflection_type_t;
@@ -299,6 +307,7 @@ static void reflection_free_objects_storage(zend_object *object) /* {{{ */
reflection_object *intern = reflection_object_from_obj(object);
parameter_reference *reference;
property_reference *prop_reference;
+ type_reference *typ_reference;
if (intern->ptr) {
switch (intern->ref_type) {
@@ -307,6 +316,11 @@ static void reflection_free_objects_storage(zend_object *object) /* {{{ */
_free_function(reference->fptr);
efree(intern->ptr);
break;
+ case REF_TYPE_TYPE:
+ typ_reference = (type_reference*)intern->ptr;
+ _free_function(typ_reference->fptr);
+ efree(intern->ptr);
+ break;
case REF_TYPE_FUNCTION:
_free_function(intern->ptr);
break;
@@ -1236,6 +1250,27 @@ static void reflection_parameter_factory(zend_function *fptr, zval *closure_obje
}
/* }}} */
+/* {{{ reflection_type_factory */
+static void reflection_type_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, zval *object)
+{
+ reflection_object *intern;
+ type_reference *reference;
+
+ reflection_instantiate(reflection_type_ptr, object);
+ intern = Z_REFLECTION_P(object);
+ reference = (type_reference*) emalloc(sizeof(type_reference));
+ reference->arg_info = arg_info;
+ reference->fptr = fptr;
+ intern->ptr = reference;
+ intern->ref_type = REF_TYPE_TYPE;
+ intern->ce = fptr->common.scope;
+ if (closure_object) {
+ Z_ADDREF_P(closure_object);
+ ZVAL_COPY_VALUE(&intern->obj, closure_object);
+ }
+}
+/* }}} */
+
/* {{{ reflection_function_factory */
static void reflection_function_factory(zend_function *function, zval *closure_object, zval *object)
{
@@ -1685,7 +1720,7 @@ ZEND_METHOD(reflection_function, getClosureThis)
if (!Z_ISUNDEF(intern->obj)) {
closure_this = zend_get_closure_this_ptr(&intern->obj);
if (!Z_ISUNDEF_P(closure_this)) {
- RETURN_ZVAL(closure_this, 1, 0);
+ ZVAL_COPY(return_value, closure_this);
}
}
}
@@ -2504,6 +2539,7 @@ ZEND_METHOD(reflection_parameter, __toString)
_parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "");
RETURN_NEW_STR(str.buf);
}
+
/* }}} */
/* {{{ proto public string ReflectionParameter::getName()
@@ -2538,7 +2574,7 @@ ZEND_METHOD(reflection_parameter, getDeclaringFunction)
/* }}} */
/* {{{ proto public ReflectionClass|NULL ReflectionParameter::getDeclaringClass()
- Returns in which class this parameter is defined (not the typehint of the parameter) */
+ Returns in which class this parameter is defined (not the type of the parameter) */
ZEND_METHOD(reflection_parameter, getDeclaringClass)
{
reflection_object *intern;
@@ -2630,6 +2666,44 @@ ZEND_METHOD(reflection_parameter, getClass)
}
/* }}} */
+/* {{{ proto public bool ReflectionParameter::hasType()
+ Returns whether parameter has a type */
+ZEND_METHOD(reflection_parameter, hasType)
+{
+ reflection_object *intern;
+ parameter_reference *param;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ RETVAL_BOOL(param->arg_info->type_hint != 0);
+}
+/* }}} */
+
+/* {{{ proto public ReflectionType ReflectionParameter::getType()
+ Returns the type associated with the parameter */
+ZEND_METHOD(reflection_parameter, getType)
+{
+ reflection_object *intern;
+ parameter_reference *param;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ if ((param->fptr->type == ZEND_INTERNAL_FUNCTION ?
+ ((zend_internal_arg_info*)param->arg_info)->type_hint :
+ param->arg_info->type_hint) == 0)
+ {
+ RETURN_NULL();
+ }
+ reflection_type_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, param->arg_info, return_value);
+}
+/* }}} */
+
/* {{{ proto public bool ReflectionParameter::isArray()
Returns whether parameter MUST be an array */
ZEND_METHOD(reflection_parameter, isArray)
@@ -2867,6 +2941,69 @@ ZEND_METHOD(reflection_parameter, isVariadic)
}
/* }}} */
+/* {{{ proto public bool ReflectionType::allowsNull()
+ Returns whether parameter MAY be null */
+ZEND_METHOD(reflection_type, allowsNull)
+{
+ reflection_object *intern;
+ type_reference *param;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ RETVAL_BOOL(param->arg_info->allow_null);
+}
+/* }}} */
+
+/* {{{ proto public bool ReflectionType::isBuiltin()
+ Returns whether parameter is a builtin type */
+ZEND_METHOD(reflection_type, isBuiltin)
+{
+ reflection_object *intern;
+ type_reference *param;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ RETVAL_BOOL(param->arg_info->type_hint != IS_OBJECT);
+}
+/* }}} */
+
+/* {{{ proto public string ReflectionType::__toString()
+ Return the text of the type hint */
+ZEND_METHOD(reflection_type, __toString)
+{
+ reflection_object *intern;
+ type_reference *param;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+ GET_REFLECTION_OBJECT_PTR(param);
+
+ switch (param->arg_info->type_hint) {
+ case IS_ARRAY: RETURN_STRINGL("array", sizeof("array") - 1);
+ case IS_CALLABLE: RETURN_STRINGL("callable", sizeof("callable") - 1);
+ case IS_OBJECT:
+ if (param->fptr->type == ZEND_INTERNAL_FUNCTION) {
+ if (!(param->fptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
+ RETURN_STRING(((zend_internal_arg_info*)param->arg_info)->class_name);
+ }
+ }
+ RETURN_STR_COPY(param->arg_info->class_name);
+ case IS_STRING: RETURN_STRINGL("string", sizeof("string") - 1);
+ case _IS_BOOL: RETURN_STRINGL("bool", sizeof("bool") - 1);
+ case IS_LONG: RETURN_STRINGL("int", sizeof("int") - 1);
+ case IS_DOUBLE: RETURN_STRINGL("float", sizeof("float") - 1);
+ EMPTY_SWITCH_DEFAULT_CASE()
+ }
+}
+/* }}} */
+
/* {{{ 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)
@@ -3016,7 +3153,7 @@ ZEND_METHOD(reflection_method, getClosure)
if (Z_OBJCE_P(obj) == zend_ce_closure &&
(mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
{
- RETURN_ZVAL(obj, 1, 0);
+ ZVAL_COPY(return_value, obj);
} else {
zend_create_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), obj);
}
@@ -3375,7 +3512,46 @@ ZEND_METHOD(reflection_function, getShortName)
{
RETURN_STRINGL(backslash + 1, Z_STRLEN_P(name) - (backslash - Z_STRVAL_P(name) + 1));
}
- RETURN_ZVAL(name, 1, 0);
+ ZVAL_DEREF(name);
+ ZVAL_COPY(return_value, name);
+}
+/* }}} */
+
+/* {{{ proto public bool ReflectionFunctionAbstract:hasReturnType()
+ Return whether the function has a return type */
+ZEND_METHOD(reflection_function, hasReturnType)
+{
+ reflection_object *intern;
+ zend_function *fptr;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ GET_REFLECTION_OBJECT_PTR(fptr);
+
+ RETVAL_BOOL(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE);
+}
+/* }}} */
+
+/* {{{ proto public string ReflectionFunctionAbstract::getReturnType()
+ Returns the return type associated with the function */
+ZEND_METHOD(reflection_function, getReturnType)
+{
+ reflection_object *intern;
+ zend_function *fptr;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ GET_REFLECTION_OBJECT_PTR(fptr);
+
+ if (!(fptr->op_array.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
+ RETURN_NULL();
+ }
+
+ reflection_type_factory(_copy_function(fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, &fptr->common.arg_info[-1], return_value);
}
/* }}} */
@@ -3644,14 +3820,15 @@ ZEND_METHOD(reflection_class, getStaticPropertyValue)
prop = zend_std_get_static_property(ce, name, 1);
if (!prop) {
if (def_value) {
- RETURN_ZVAL(def_value, 1, 0);
+ ZVAL_COPY(return_value, def_value);
} else {
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Class %s does not have a property named %s", ce->name->val, name->val);
}
return;
} else {
- RETURN_ZVAL(prop, 1, 0);
+ ZVAL_DEREF(prop);
+ ZVAL_COPY(return_value, prop);
}
}
/* }}} */
@@ -4963,7 +5140,8 @@ ZEND_METHOD(reflection_class, getShortName)
{
RETURN_STRINGL(backslash + 1, Z_STRLEN_P(name) - (backslash - Z_STRVAL_P(name) + 1));
}
- RETURN_ZVAL(name, 1, 0);
+ ZVAL_DEREF(name);
+ ZVAL_COPY(return_value, name);
}
/* }}} */
@@ -5984,6 +6162,8 @@ static const zend_function_entry reflection_function_abstract_functions[] = {
ZEND_ME(reflection_function, getStartLine, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, getStaticVariables, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, returnsReference, arginfo_reflection__void, 0)
+ ZEND_ME(reflection_function, hasReturnType, arginfo_reflection__void, 0)
+ ZEND_ME(reflection_function, getReturnType, arginfo_reflection__void, 0)
PHP_FE_END
};
@@ -6064,7 +6244,7 @@ static const zend_function_entry reflection_method_functions[] = {
ZEND_ME(reflection_method, invokeArgs, arginfo_reflection_method_invokeArgs, 0)
ZEND_ME(reflection_method, getDeclaringClass, arginfo_reflection__void, 0)
ZEND_ME(reflection_method, getPrototype, arginfo_reflection__void, 0)
- ZEND_ME(reflection_property, setAccessible, arginfo_reflection_method_setAccessible, 0)
+ ZEND_ME(reflection_method, setAccessible, arginfo_reflection_method_setAccessible, 0)
PHP_FE_END
};
@@ -6281,6 +6461,8 @@ static const zend_function_entry reflection_parameter_functions[] = {
ZEND_ME(reflection_parameter, getDeclaringFunction, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, getDeclaringClass, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, getClass, arginfo_reflection__void, 0)
+ ZEND_ME(reflection_parameter, hasType, arginfo_reflection__void, 0)
+ ZEND_ME(reflection_parameter, getType, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, isArray, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, isCallable, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, allowsNull, arginfo_reflection__void, 0)
@@ -6294,6 +6476,14 @@ static const zend_function_entry reflection_parameter_functions[] = {
PHP_FE_END
};
+static const zend_function_entry reflection_type_functions[] = {
+ ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
+ ZEND_ME(reflection_type, allowsNull, arginfo_reflection__void, 0)
+ ZEND_ME(reflection_type, isBuiltin, arginfo_reflection__void, 0)
+ ZEND_ME(reflection_type, __toString, arginfo_reflection__void, 0)
+ PHP_FE_END
+};
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_extension_export, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, return)
@@ -6407,6 +6597,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
zend_class_implements(reflection_parameter_ptr, 1, reflector_ptr);
zend_declare_property_string(reflection_parameter_ptr, "name", sizeof("name")-1, "", ZEND_ACC_PUBLIC);
+ INIT_CLASS_ENTRY(_reflection_entry, "ReflectionType", reflection_type_functions);
+ _reflection_entry.create_object = reflection_objects_new;
+ reflection_type_ptr = zend_register_internal_class(&_reflection_entry);
+
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionMethod", reflection_method_functions);
_reflection_entry.create_object = reflection_objects_new;
reflection_method_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_function_abstract_ptr);