mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
ReflectionType improvements
Added ReflectionNamedType and updated ReflectionType::__toString()
This commit is contained in:
committed by
Nikita Popov
parent
283b0cc8a5
commit
622d2f41d1
4
NEWS
4
NEWS
@@ -28,7 +28,9 @@ PHP NEWS
|
||||
|
||||
- Reflection:
|
||||
. Implemented request #38992 (invoke() and invokeArgs() static method calls
|
||||
should match). (cmb)
|
||||
should match). (cmb).
|
||||
. Add ReflectionNamedType::getName() and return leading "?" for nullable types
|
||||
from ReflectionType::__toString(). (Trowski)
|
||||
|
||||
- SQLite3:
|
||||
. Updated to SQLite3 3.14.0. (cmb)
|
||||
|
||||
@@ -93,6 +93,9 @@ PHP 7.1 UPGRADE NOTES
|
||||
. The behavior of ReflectionMethod::invoke() and ::invokeArgs() has been
|
||||
aligned, what causes slightly different behavior than before for some
|
||||
pathological cases.
|
||||
. ReflectionType::__toString() will now return the type name with a leading
|
||||
"?" if it is nullable. To retrieve the type name without leading "?" the new
|
||||
ReflectionNamedType::getName() method can be used.
|
||||
|
||||
========================================
|
||||
2. New Features
|
||||
|
||||
@@ -60,6 +60,7 @@ 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_named_type_ptr;
|
||||
PHPAPI zend_class_entry *reflection_class_ptr;
|
||||
PHPAPI zend_class_entry *reflection_object_ptr;
|
||||
PHPAPI zend_class_entry *reflection_method_ptr;
|
||||
@@ -1276,7 +1277,7 @@ static void reflection_type_factory(zend_function *fptr, zval *closure_object, s
|
||||
reflection_object *intern;
|
||||
type_reference *reference;
|
||||
|
||||
reflection_instantiate(reflection_type_ptr, object);
|
||||
reflection_instantiate(reflection_named_type_ptr, object);
|
||||
intern = Z_REFLECTION_P(object);
|
||||
reference = (type_reference*) emalloc(sizeof(type_reference));
|
||||
reference->arg_info = arg_info;
|
||||
@@ -2999,35 +3000,66 @@ ZEND_METHOD(reflection_type, isBuiltin)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ reflection_type_name */
|
||||
static zend_string *reflection_type_name(type_reference *param) {
|
||||
switch (param->arg_info->type_hint) {
|
||||
case IS_ARRAY: return zend_string_init("array", sizeof("array") - 1, 0);
|
||||
case IS_CALLABLE: return zend_string_init("callable", sizeof("callable") - 1, 0);
|
||||
case IS_OBJECT:
|
||||
if (param->fptr->type == ZEND_INTERNAL_FUNCTION &&
|
||||
!(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
|
||||
return zend_string_init(((zend_internal_arg_info*)param->arg_info)->class_name, strlen(((zend_internal_arg_info*)param->arg_info)->class_name), 0);
|
||||
}
|
||||
return zend_string_copy(param->arg_info->class_name);
|
||||
case IS_STRING: return zend_string_init("string", sizeof("string") - 1, 0);
|
||||
case _IS_BOOL: return zend_string_init("bool", sizeof("bool") - 1, 0);
|
||||
case IS_LONG: return zend_string_init("int", sizeof("int") - 1, 0);
|
||||
case IS_DOUBLE: return zend_string_init("float", sizeof("float") - 1, 0);
|
||||
case IS_VOID: return zend_string_init("void", sizeof("void") - 1, 0);
|
||||
case IS_ITERABLE: return zend_string_init("iterable", sizeof("iterable") - 1, 0);
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto public string ReflectionType::__toString()
|
||||
Return the text of the type hint */
|
||||
ZEND_METHOD(reflection_type, __toString)
|
||||
{
|
||||
reflection_object *intern;
|
||||
type_reference *param;
|
||||
zend_string *str;
|
||||
|
||||
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 &&
|
||||
!(param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO)) {
|
||||
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);
|
||||
case IS_VOID: RETURN_STRINGL("void", sizeof("void") - 1);
|
||||
case IS_ITERABLE: RETURN_STRINGL("iterable", sizeof("iterable") - 1);
|
||||
EMPTY_SWITCH_DEFAULT_CASE()
|
||||
|
||||
str = reflection_type_name(param);
|
||||
|
||||
if (param->arg_info->allow_null) {
|
||||
str = zend_string_extend(str, ZSTR_LEN(str) + 1, 0);
|
||||
memmove(ZSTR_VAL(str) + 1, ZSTR_VAL(str), ZSTR_LEN(str) + 1);
|
||||
ZSTR_VAL(str)[0] = '?';
|
||||
}
|
||||
|
||||
RETURN_STR(str);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto public string ReflectionNamedType::getName()
|
||||
Return the text of the type hint */
|
||||
ZEND_METHOD(reflection_named_type, getName)
|
||||
{
|
||||
reflection_object *intern;
|
||||
type_reference *param;
|
||||
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
GET_REFLECTION_OBJECT_PTR(param);
|
||||
|
||||
RETURN_STR(reflection_type_name(param));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
@@ -6688,6 +6720,11 @@ static const zend_function_entry reflection_type_functions[] = {
|
||||
PHP_FE_END
|
||||
};
|
||||
|
||||
static const zend_function_entry reflection_named_type_functions[] = {
|
||||
ZEND_ME(reflection_named_type, getName, 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)
|
||||
@@ -6804,6 +6841,10 @@ PHP_MINIT_FUNCTION(reflection) /* {{{ */
|
||||
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, "ReflectionNamedType", reflection_named_type_functions);
|
||||
_reflection_entry.create_object = reflection_objects_new;
|
||||
reflection_named_type_ptr = zend_register_internal_class_ex(&_reflection_entry, reflection_type_ptr);
|
||||
|
||||
INIT_CLASS_ENTRY(_reflection_entry, "ReflectionMethod", reflection_method_functions);
|
||||
_reflection_entry.create_object = reflection_objects_new;
|
||||
|
||||
@@ -38,6 +38,7 @@ extern PHPAPI zend_class_entry *reflection_function_abstract_ptr;
|
||||
extern PHPAPI zend_class_entry *reflection_function_ptr;
|
||||
extern PHPAPI zend_class_entry *reflection_parameter_ptr;
|
||||
extern PHPAPI zend_class_entry *reflection_type_ptr;
|
||||
extern PHPAPI zend_class_entry *reflection_named_type_ptr;
|
||||
extern PHPAPI zend_class_entry *reflection_class_ptr;
|
||||
extern PHPAPI zend_class_entry *reflection_object_ptr;
|
||||
extern PHPAPI zend_class_entry *reflection_method_ptr;
|
||||
|
||||
@@ -9,7 +9,7 @@ var_dump($ext->getClasses());
|
||||
?>
|
||||
==DONE==
|
||||
--EXPECT--
|
||||
array(15) {
|
||||
array(16) {
|
||||
["ReflectionException"]=>
|
||||
object(ReflectionClass)#2 (1) {
|
||||
["name"]=>
|
||||
@@ -50,38 +50,43 @@ array(15) {
|
||||
["name"]=>
|
||||
string(14) "ReflectionType"
|
||||
}
|
||||
["ReflectionMethod"]=>
|
||||
["ReflectionNamedType"]=>
|
||||
object(ReflectionClass)#10 (1) {
|
||||
["name"]=>
|
||||
string(19) "ReflectionNamedType"
|
||||
}
|
||||
["ReflectionMethod"]=>
|
||||
object(ReflectionClass)#11 (1) {
|
||||
["name"]=>
|
||||
string(16) "ReflectionMethod"
|
||||
}
|
||||
["ReflectionClass"]=>
|
||||
object(ReflectionClass)#11 (1) {
|
||||
object(ReflectionClass)#12 (1) {
|
||||
["name"]=>
|
||||
string(15) "ReflectionClass"
|
||||
}
|
||||
["ReflectionObject"]=>
|
||||
object(ReflectionClass)#12 (1) {
|
||||
object(ReflectionClass)#13 (1) {
|
||||
["name"]=>
|
||||
string(16) "ReflectionObject"
|
||||
}
|
||||
["ReflectionProperty"]=>
|
||||
object(ReflectionClass)#13 (1) {
|
||||
object(ReflectionClass)#14 (1) {
|
||||
["name"]=>
|
||||
string(18) "ReflectionProperty"
|
||||
}
|
||||
["ReflectionClassConstant"]=>
|
||||
object(ReflectionClass)#14 (1) {
|
||||
object(ReflectionClass)#15 (1) {
|
||||
["name"]=>
|
||||
string(23) "ReflectionClassConstant"
|
||||
}
|
||||
["ReflectionExtension"]=>
|
||||
object(ReflectionClass)#15 (1) {
|
||||
object(ReflectionClass)#16 (1) {
|
||||
["name"]=>
|
||||
string(19) "ReflectionExtension"
|
||||
}
|
||||
["ReflectionZendExtension"]=>
|
||||
object(ReflectionClass)#16 (1) {
|
||||
object(ReflectionClass)#17 (1) {
|
||||
["name"]=>
|
||||
string(23) "ReflectionZendExtension"
|
||||
}
|
||||
|
||||
41
ext/reflection/tests/ReflectionNamedType.phpt
Normal file
41
ext/reflection/tests/ReflectionNamedType.phpt
Normal file
@@ -0,0 +1,41 @@
|
||||
--TEST--
|
||||
ReflectionNamedType::getName() and ReflectionNamedType::__toString()
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function testInternalTypes(?Traversable $traversable): ?string {
|
||||
return 'test';
|
||||
}
|
||||
|
||||
function testUserDefinedTypes(?Test $traversable): ?Test {
|
||||
return new Test;
|
||||
}
|
||||
|
||||
$function = new ReflectionFunction('testInternalTypes');
|
||||
$type = $function->getParameters()[0]->getType();
|
||||
$return = $function->getReturnType();
|
||||
|
||||
var_dump($type->getName());
|
||||
var_dump((string) $type);
|
||||
var_dump($return->getName());
|
||||
var_dump((string) $return);
|
||||
|
||||
$function = new ReflectionFunction('testUserDefinedTypes');
|
||||
$type = $function->getParameters()[0]->getType();
|
||||
$return = $function->getReturnType();
|
||||
|
||||
var_dump($type->getName());
|
||||
var_dump((string) $type);
|
||||
var_dump($return->getName());
|
||||
var_dump((string) $return);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
string(11) "Traversable"
|
||||
string(12) "?Traversable"
|
||||
string(6) "string"
|
||||
string(7) "?string"
|
||||
string(4) "Test"
|
||||
string(5) "?Test"
|
||||
string(4) "Test"
|
||||
string(5) "?Test"
|
||||
@@ -94,7 +94,7 @@ string(8) "callable"
|
||||
bool(true)
|
||||
bool(true)
|
||||
bool(false)
|
||||
string(8) "stdClass"
|
||||
string(9) "?stdClass"
|
||||
** Function 0 - Parameter 4
|
||||
bool(false)
|
||||
** Function 0 - Parameter 5
|
||||
|
||||
Reference in New Issue
Block a user