Skip to content

Commit 622d2f4

Browse files
trowskinikic
authored andcommitted
ReflectionType improvements
Added ReflectionNamedType and updated ReflectionType::__toString()
1 parent 283b0cc commit 622d2f4

7 files changed

Lines changed: 120 additions & 27 deletions

File tree

NEWS

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ PHP NEWS
2828

2929
- Reflection:
3030
. Implemented request #38992 (invoke() and invokeArgs() static method calls
31-
should match). (cmb)
31+
should match). (cmb).
32+
. Add ReflectionNamedType::getName() and return leading "?" for nullable types
33+
from ReflectionType::__toString(). (Trowski)
3234

3335
- SQLite3:
3436
. Updated to SQLite3 3.14.0. (cmb)

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ PHP 7.1 UPGRADE NOTES
9393
. The behavior of ReflectionMethod::invoke() and ::invokeArgs() has been
9494
aligned, what causes slightly different behavior than before for some
9595
pathological cases.
96+
. ReflectionType::__toString() will now return the type name with a leading
97+
"?" if it is nullable. To retrieve the type name without leading "?" the new
98+
ReflectionNamedType::getName() method can be used.
9699

97100
========================================
98101
2. New Features

ext/reflection/php_reflection.c

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ PHPAPI zend_class_entry *reflection_function_ptr;
6060
PHPAPI zend_class_entry *reflection_generator_ptr;
6161
PHPAPI zend_class_entry *reflection_parameter_ptr;
6262
PHPAPI zend_class_entry *reflection_type_ptr;
63+
PHPAPI zend_class_entry *reflection_named_type_ptr;
6364
PHPAPI zend_class_entry *reflection_class_ptr;
6465
PHPAPI zend_class_entry *reflection_object_ptr;
6566
PHPAPI zend_class_entry *reflection_method_ptr;
@@ -1276,7 +1277,7 @@ static void reflection_type_factory(zend_function *fptr, zval *closure_object, s
12761277
reflection_object *intern;
12771278
type_reference *reference;
12781279

1279-
reflection_instantiate(reflection_type_ptr, object);
1280+
reflection_instantiate(reflection_named_type_ptr, object);
12801281
intern = Z_REFLECTION_P(object);
12811282
reference = (type_reference*) emalloc(sizeof(type_reference));
12821283
reference->arg_info = arg_info;
@@ -2999,35 +3000,66 @@ ZEND_METHOD(reflection_type, isBuiltin)
29993000
}
30003001
/* }}} */
30013002

3003+
/* {{{ reflection_type_name */
3004+
static zend_string *reflection_type_name(type_reference *param) {
3005+
switch (param->arg_info->type_hint) {
3006+
case IS_ARRAY: return zend_string_init("array", sizeof("array") - 1, 0);
3007+
case IS_CALLABLE: return zend_string_init("callable", sizeof("callable") - 1, 0);
3008+
case IS_OBJECT:
3009+
if (param->fptr->type == ZEND_INTERNAL_FUNCTION &&
3010+
!(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
3011+
return zend_string_init(((zend_internal_arg_info*)param->arg_info)->class_name, strlen(((zend_internal_arg_info*)param->arg_info)->class_name), 0);
3012+
}
3013+
return zend_string_copy(param->arg_info->class_name);
3014+
case IS_STRING: return zend_string_init("string", sizeof("string") - 1, 0);
3015+
case _IS_BOOL: return zend_string_init("bool", sizeof("bool") - 1, 0);
3016+
case IS_LONG: return zend_string_init("int", sizeof("int") - 1, 0);
3017+
case IS_DOUBLE: return zend_string_init("float", sizeof("float") - 1, 0);
3018+
case IS_VOID: return zend_string_init("void", sizeof("void") - 1, 0);
3019+
case IS_ITERABLE: return zend_string_init("iterable", sizeof("iterable") - 1, 0);
3020+
EMPTY_SWITCH_DEFAULT_CASE()
3021+
}
3022+
}
3023+
/* }}} */
3024+
30023025
/* {{{ proto public string ReflectionType::__toString()
30033026
Return the text of the type hint */
30043027
ZEND_METHOD(reflection_type, __toString)
30053028
{
30063029
reflection_object *intern;
30073030
type_reference *param;
3031+
zend_string *str;
30083032

30093033
if (zend_parse_parameters_none() == FAILURE) {
30103034
return;
30113035
}
30123036
GET_REFLECTION_OBJECT_PTR(param);
3037+
3038+
str = reflection_type_name(param);
3039+
3040+
if (param->arg_info->allow_null) {
3041+
str = zend_string_extend(str, ZSTR_LEN(str) + 1, 0);
3042+
memmove(ZSTR_VAL(str) + 1, ZSTR_VAL(str), ZSTR_LEN(str) + 1);
3043+
ZSTR_VAL(str)[0] = '?';
3044+
}
3045+
3046+
RETURN_STR(str);
3047+
}
3048+
/* }}} */
30133049

3014-
switch (param->arg_info->type_hint) {
3015-
case IS_ARRAY: RETURN_STRINGL("array", sizeof("array") - 1);
3016-
case IS_CALLABLE: RETURN_STRINGL("callable", sizeof("callable") - 1);
3017-
case IS_OBJECT:
3018-
if (param->fptr->type == ZEND_INTERNAL_FUNCTION &&
3019-
!(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
3020-
RETURN_STRING(((zend_internal_arg_info*)param->arg_info)->class_name);
3021-
}
3022-
RETURN_STR_COPY(param->arg_info->class_name);
3023-
case IS_STRING: RETURN_STRINGL("string", sizeof("string") - 1);
3024-
case _IS_BOOL: RETURN_STRINGL("bool", sizeof("bool") - 1);
3025-
case IS_LONG: RETURN_STRINGL("int", sizeof("int") - 1);
3026-
case IS_DOUBLE: RETURN_STRINGL("float", sizeof("float") - 1);
3027-
case IS_VOID: RETURN_STRINGL("void", sizeof("void") - 1);
3028-
case IS_ITERABLE: RETURN_STRINGL("iterable", sizeof("iterable") - 1);
3029-
EMPTY_SWITCH_DEFAULT_CASE()
3050+
/* {{{ proto public string ReflectionNamedType::getName()
3051+
Return the text of the type hint */
3052+
ZEND_METHOD(reflection_named_type, getName)
3053+
{
3054+
reflection_object *intern;
3055+
type_reference *param;
3056+
3057+
if (zend_parse_parameters_none() == FAILURE) {
3058+
return;
30303059
}
3060+
GET_REFLECTION_OBJECT_PTR(param);
3061+
3062+
RETURN_STR(reflection_type_name(param));
30313063
}
30323064
/* }}} */
30333065

@@ -6688,6 +6720,11 @@ static const zend_function_entry reflection_type_functions[] = {
66886720
PHP_FE_END
66896721
};
66906722

6723+
static const zend_function_entry reflection_named_type_functions[] = {
6724+
ZEND_ME(reflection_named_type, getName, arginfo_reflection__void, 0)
6725+
PHP_FE_END
6726+
};
6727+
66916728
ZEND_BEGIN_ARG_INFO_EX(arginfo_reflection_extension_export, 0, 0, 1)
66926729
ZEND_ARG_INFO(0, name)
66936730
ZEND_ARG_INFO(0, return)
@@ -6804,6 +6841,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
68046841
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionType", reflection_type_functions);
68056842
_reflection_entry.create_object = reflection_objects_new;
68066843
reflection_type_ptr = zend_register_internal_class(&_reflection_entry);
6844+
6845+
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionNamedType", reflection_named_type_functions);
6846+
_reflection_entry.create_object = reflection_objects_new;
6847+
reflection_named_type_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_type_ptr);
68076848

68086849
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionMethod", reflection_method_functions);
68096850
_reflection_entry.create_object = reflection_objects_new;

ext/reflection/php_reflection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extern PHPAPI zend_class_entry *reflection_function_abstract_ptr;
3838
extern PHPAPI zend_class_entry *reflection_function_ptr;
3939
extern PHPAPI zend_class_entry *reflection_parameter_ptr;
4040
extern PHPAPI zend_class_entry *reflection_type_ptr;
41+
extern PHPAPI zend_class_entry *reflection_named_type_ptr;
4142
extern PHPAPI zend_class_entry *reflection_class_ptr;
4243
extern PHPAPI zend_class_entry *reflection_object_ptr;
4344
extern PHPAPI zend_class_entry *reflection_method_ptr;

ext/reflection/tests/ReflectionExtension_getClasses_basic.phpt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ var_dump($ext->getClasses());
99
?>
1010
==DONE==
1111
--EXPECT--
12-
array(15) {
12+
array(16) {
1313
["ReflectionException"]=>
1414
object(ReflectionClass)#2 (1) {
1515
["name"]=>
@@ -50,38 +50,43 @@ array(15) {
5050
["name"]=>
5151
string(14) "ReflectionType"
5252
}
53-
["ReflectionMethod"]=>
53+
["ReflectionNamedType"]=>
5454
object(ReflectionClass)#10 (1) {
55+
["name"]=>
56+
string(19) "ReflectionNamedType"
57+
}
58+
["ReflectionMethod"]=>
59+
object(ReflectionClass)#11 (1) {
5560
["name"]=>
5661
string(16) "ReflectionMethod"
5762
}
5863
["ReflectionClass"]=>
59-
object(ReflectionClass)#11 (1) {
64+
object(ReflectionClass)#12 (1) {
6065
["name"]=>
6166
string(15) "ReflectionClass"
6267
}
6368
["ReflectionObject"]=>
64-
object(ReflectionClass)#12 (1) {
69+
object(ReflectionClass)#13 (1) {
6570
["name"]=>
6671
string(16) "ReflectionObject"
6772
}
6873
["ReflectionProperty"]=>
69-
object(ReflectionClass)#13 (1) {
74+
object(ReflectionClass)#14 (1) {
7075
["name"]=>
7176
string(18) "ReflectionProperty"
7277
}
7378
["ReflectionClassConstant"]=>
74-
object(ReflectionClass)#14 (1) {
79+
object(ReflectionClass)#15 (1) {
7580
["name"]=>
7681
string(23) "ReflectionClassConstant"
7782
}
7883
["ReflectionExtension"]=>
79-
object(ReflectionClass)#15 (1) {
84+
object(ReflectionClass)#16 (1) {
8085
["name"]=>
8186
string(19) "ReflectionExtension"
8287
}
8388
["ReflectionZendExtension"]=>
84-
object(ReflectionClass)#16 (1) {
89+
object(ReflectionClass)#17 (1) {
8590
["name"]=>
8691
string(23) "ReflectionZendExtension"
8792
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
ReflectionNamedType::getName() and ReflectionNamedType::__toString()
3+
--FILE--
4+
<?php
5+
6+
function testInternalTypes(?Traversable $traversable): ?string {
7+
return 'test';
8+
}
9+
10+
function testUserDefinedTypes(?Test $traversable): ?Test {
11+
return new Test;
12+
}
13+
14+
$function = new ReflectionFunction('testInternalTypes');
15+
$type = $function->getParameters()[0]->getType();
16+
$return = $function->getReturnType();
17+
18+
var_dump($type->getName());
19+
var_dump((string) $type);
20+
var_dump($return->getName());
21+
var_dump((string) $return);
22+
23+
$function = new ReflectionFunction('testUserDefinedTypes');
24+
$type = $function->getParameters()[0]->getType();
25+
$return = $function->getReturnType();
26+
27+
var_dump($type->getName());
28+
var_dump((string) $type);
29+
var_dump($return->getName());
30+
var_dump((string) $return);
31+
32+
?>
33+
--EXPECTF--
34+
string(11) "Traversable"
35+
string(12) "?Traversable"
36+
string(6) "string"
37+
string(7) "?string"
38+
string(4) "Test"
39+
string(5) "?Test"
40+
string(4) "Test"
41+
string(5) "?Test"

ext/reflection/tests/ReflectionType_001.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ string(8) "callable"
9494
bool(true)
9595
bool(true)
9696
bool(false)
97-
string(8) "stdClass"
97+
string(9) "?stdClass"
9898
** Function 0 - Parameter 4
9999
bool(false)
100100
** Function 0 - Parameter 5

0 commit comments

Comments
 (0)