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_typeannotation_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;
zend_function *fptr;
} parameter_reference;
-/* Struct for type annotations */
-typedef struct _typeannotation_reference {
+/* Struct for type hints */
+typedef struct _type_reference {
struct _zend_arg_info *arg_info;
-} typeannotation_reference;
+ zend_function *fptr;
+} type_reference;
typedef enum {
REF_TYPE_OTHER, /* Must be 0 */
REF_TYPE_FUNCTION,
REF_TYPE_GENERATOR,
REF_TYPE_PARAMETER,
- REF_TYPE_ANNOTATION,
+ REF_TYPE_TYPE,
REF_TYPE_PROPERTY,
REF_TYPE_DYNAMIC_PROPERTY
} reflection_type_t;
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) {
case REF_TYPE_PARAMETER:
reference = (parameter_reference*)intern->ptr;
_free_function(reference->fptr);
- /* fallthrough */
- case REF_TYPE_ANNOTATION:
+ 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:
}
/* }}} */
-/* {{{ reflection_typeannotation_factory */
-static void reflection_typeannotation_factory(zend_function *fptr, zval *closure_object, struct _zend_arg_info *arg_info, zval *object)
+/* {{{ 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;
- typeannotation_reference *reference;
+ type_reference *reference;
- reflection_instantiate(reflection_typeannotation_ptr, object);
+ reflection_instantiate(reflection_type_ptr, object);
intern = Z_REFLECTION_P(object);
- reference = (typeannotation_reference*) emalloc(sizeof(typeannotation_reference));
+ reference = (type_reference*) emalloc(sizeof(type_reference));
reference->arg_info = arg_info;
+ reference->fptr = fptr;
intern->ptr = reference;
- intern->ref_type = REF_TYPE_ANNOTATION;
+ intern->ref_type = REF_TYPE_TYPE;
intern->ce = fptr->common.scope;
if (closure_object) {
Z_ADDREF_P(closure_object);
_parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required, "");
RETURN_NEW_STR(str.buf);
}
+
/* }}} */
/* {{{ proto public string ReflectionParameter::getName()
/* }}} */
/* {{{ 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;
}
/* }}} */
-/* {{{ proto public bool ReflectionParameter::hasTypeAnnotation()
- Rethern whether parameter has a type hint */
-ZEND_METHOD(reflection_parameter, hasTypeAnnotation)
+/* {{{ proto public bool ReflectionParameter::hasType()
+ Returns whether parameter has a type */
+ZEND_METHOD(reflection_parameter, hasType)
{
reflection_object *intern;
parameter_reference *param;
}
/* }}} */
-/* {{{ proto public string ReflectionParameter::getTypeAnnotation()
- Returns the typehint associated with the parameter */
-ZEND_METHOD(reflection_parameter, getTypeAnnotation)
+/* {{{ proto public ReflectionType ReflectionParameter::getType()
+ Returns the type associated with the parameter */
+ZEND_METHOD(reflection_parameter, getType)
{
reflection_object *intern;
parameter_reference *param;
}
GET_REFLECTION_OBJECT_PTR(param);
- if (!param->arg_info->type_hint) {
+ 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_typeannotation_factory(param->fptr, Z_ISUNDEF(intern->obj)? NULL : &intern->obj, param->arg_info, return_value);
+ reflection_type_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, param->arg_info, return_value);
}
/* }}} */
}
/* }}} */
-/* {{{ proto public bool ReflectionTypeAnnotation::isArray()
- Returns whether parameter MUST be an array */
-ZEND_METHOD(reflection_typeannotation, isArray)
-{
- reflection_object *intern;
- typeannotation_reference *param;
-
- if (zend_parse_parameters_none() == FAILURE) {
- return;
- }
- GET_REFLECTION_OBJECT_PTR(param);
-
- RETVAL_BOOL(param->arg_info->type_hint == IS_ARRAY);
-}
-/* }}} */
-
-/* {{{ proto public bool ReflectionTypeAnnotation::isCallable()
- Returns whether parameter MUST be callable */
-ZEND_METHOD(reflection_typeannotation, isCallable)
+/* {{{ proto public bool ReflectionType::allowsNull()
+ Returns whether parameter MAY be null */
+ZEND_METHOD(reflection_type, allowsNull)
{
reflection_object *intern;
- typeannotation_reference *param;
+ type_reference *param;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(param);
- RETVAL_BOOL(param->arg_info->type_hint == IS_CALLABLE);
+ RETVAL_BOOL(param->arg_info->allow_null);
}
/* }}} */
-/* {{{ proto public bool ReflectionTypeAnnotation::isNullable()
- Returns whether parameter MAY be null */
-ZEND_METHOD(reflection_typeannotation, isNullable)
+/* {{{ proto public bool ReflectionType::isBuiltin()
+ Returns whether parameter is a builtin type */
+ZEND_METHOD(reflection_type, isBuiltin)
{
reflection_object *intern;
- typeannotation_reference *param;
+ type_reference *param;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(param);
- RETVAL_BOOL(param->arg_info->allow_null);
+ RETVAL_BOOL(param->arg_info->type_hint != IS_OBJECT);
}
/* }}} */
-/* {{{ proto public string ReflectionTypeAnnotation::__toString()
- Return the text of the type annotation */
-ZEND_METHOD(reflection_typeannotation, __toString)
+/* {{{ proto public string ReflectionType::__toString()
+ Return the text of the type hint */
+ZEND_METHOD(reflection_type, __toString)
{
reflection_object *intern;
- typeannotation_reference *param;
+ type_reference *param;
if (zend_parse_parameters_none() == FAILURE) {
return;
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: RETURN_STR(zend_string_copy(param->arg_info->class_name));
- default:
- php_error_docref(NULL, E_ERROR, "Unknown type annotation: %d", (int)param->arg_info->type_hint);
- RETURN_EMPTY_STRING();
+ 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 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);
+}
+/* }}} */
+
/* {{{ proto public bool ReflectionMethod::isConstructor()
Returns whether this method is the constructor */
ZEND_METHOD(reflection_method, isConstructor)
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
};
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
};
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, hasTypeAnnotation, arginfo_reflection__void, 0)
- ZEND_ME(reflection_parameter, getTypeAnnotation, 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)
PHP_FE_END
};
-static const zend_function_entry reflection_typeannotation_functions[] = {
+static const zend_function_entry reflection_type_functions[] = {
ZEND_ME(reflection, __clone, arginfo_reflection__void, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
- ZEND_ME(reflection_typeannotation, isArray, arginfo_reflection__void, 0)
- ZEND_ME(reflection_typeannotation, isCallable, arginfo_reflection__void, 0)
- ZEND_ME(reflection_typeannotation, isNullable, arginfo_reflection__void, 0)
- ZEND_ME(reflection_typeannotation, __toString, arginfo_reflection__void, 0)
+ 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_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, "ReflectionTypeAnnotation", reflection_typeannotation_functions);
+ INIT_CLASS_ENTRY(_reflection_entry, "ReflectionType", reflection_type_functions);
_reflection_entry.create_object = reflection_objects_new;
- reflection_typeannotation_ptr = zend_register_internal_class(&_reflection_entry);
+ 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;
--- /dev/null
+--TEST--
+ReflectionParameter::get/hasType and ReflectionType tests
+--FILE--
+<?php
+function foo(stdClass $a, array $b, callable $c, stdClass $d = null, $e = null, string $f, bool $g, int $h, float $i, NotExisting $j) { }
+
+function bar(): stdClass { return new stdClass; }
+
+class c extends stdClass {
+ function bar(self $x): int { return 1; }
+ function pbar(parent $x): int { return 1; }
+ function factory(): self { return new c; }
+ function pfactory(): parent { return new stdClass; }
+}
+
+$closure = function (Test $a): Test { return $a; };
+
+echo "*** functions\n";
+
+foreach ([
+ new ReflectionFunction('foo'),
+ new ReflectionFunction($closure),
+] as $idx => $rf) {
+ foreach ($rf->getParameters() as $idx2 => $rp) {
+ echo "** Function $idx - Parameter $idx2\n";
+ var_dump($rp->hasType());
+ $ra = $rp->getType();
+ if ($ra) {
+ var_dump($ra->allowsNull());
+ var_dump($ra->isBuiltin());
+ var_dump((string)$ra);
+ }
+ }
+}
+
+echo "\n*** methods\n";
+
+foreach ([
+ new ReflectionMethod('SplObserver', 'update'),
+ new ReflectionMethod('c', 'bar'),
+ new ReflectionMethod('c', 'pbar'),
+ new ReflectionMethod($closure, '__invoke'),
+] as $idx => $rm) {
+ foreach ($rm->getParameters() as $idx2 => $rp) {
+ echo "** Method $idx - parameter $idx2\n";
+ var_dump($rp->hasType());
+ $ra = $rp->getType();
+ if ($ra) {
+ var_dump($ra->allowsNull());
+ var_dump($ra->isBuiltin());
+ var_dump((string)$ra);
+ }
+ }
+}
+
+echo "\n*** return types\n";
+
+foreach ([
+ new ReflectionMethod('SplObserver', 'update'),
+ new ReflectionFunction('bar'),
+ new ReflectionMethod('c', 'bar'),
+ new ReflectionMethod('c', 'factory'),
+ new ReflectionMethod('c', 'pfactory'),
+ new ReflectionFunction($closure),
+ new ReflectionMethod($closure, '__invoke'),
+] as $idx => $rf) {
+ echo "** Function/method return type $idx\n";
+ var_dump($rf->hasReturnType());
+ $ra = $rf->getReturnType();
+ if ($ra) {
+ var_dump($ra->allowsNull());
+ var_dump($ra->isBuiltin());
+ var_dump((string)$ra);
+ }
+}
+--EXPECT--
+*** functions
+** Function 0 - Parameter 0
+bool(true)
+bool(false)
+bool(false)
+string(8) "stdClass"
+** Function 0 - Parameter 1
+bool(true)
+bool(false)
+bool(true)
+string(5) "array"
+** Function 0 - Parameter 2
+bool(true)
+bool(false)
+bool(true)
+string(8) "callable"
+** Function 0 - Parameter 3
+bool(true)
+bool(true)
+bool(false)
+string(8) "stdClass"
+** Function 0 - Parameter 4
+bool(false)
+** Function 0 - Parameter 5
+bool(true)
+bool(false)
+bool(true)
+string(6) "string"
+** Function 0 - Parameter 6
+bool(true)
+bool(false)
+bool(true)
+string(4) "bool"
+** Function 0 - Parameter 7
+bool(true)
+bool(false)
+bool(true)
+string(3) "int"
+** Function 0 - Parameter 8
+bool(true)
+bool(false)
+bool(true)
+string(5) "float"
+** Function 0 - Parameter 9
+bool(true)
+bool(false)
+bool(false)
+string(11) "NotExisting"
+** Function 1 - Parameter 0
+bool(true)
+bool(false)
+bool(false)
+string(4) "Test"
+
+*** methods
+** Method 0 - parameter 0
+bool(true)
+bool(false)
+bool(false)
+string(10) "SplSubject"
+** Method 1 - parameter 0
+bool(true)
+bool(false)
+bool(false)
+string(4) "self"
+** Method 2 - parameter 0
+bool(true)
+bool(false)
+bool(false)
+string(6) "parent"
+** Method 3 - parameter 0
+bool(true)
+bool(false)
+bool(false)
+string(4) "Test"
+
+*** return types
+** Function/method return type 0
+bool(false)
+** Function/method return type 1
+bool(true)
+bool(false)
+bool(false)
+string(8) "stdClass"
+** Function/method return type 2
+bool(true)
+bool(false)
+bool(true)
+string(3) "int"
+** Function/method return type 3
+bool(true)
+bool(false)
+bool(false)
+string(4) "self"
+** Function/method return type 4
+bool(true)
+bool(false)
+bool(false)
+string(6) "parent"
+** Function/method return type 5
+bool(true)
+bool(false)
+bool(false)
+string(4) "Test"
+** Function/method return type 6
+bool(true)
+bool(false)
+bool(false)
+string(4) "Test"