Typed class constants (#10444)

RFC: https://wiki.php.net/rfc/typed_class_constants

Co-Authored-By: Ben <7127204+moliata@users.noreply.github.com>
Co-Authored-By: Bob Weinand <3154871+bwoebi@users.noreply.github.com>
Co-Authored-By: Ilija Tovilo <ilija.tovilo@me.com>
This commit is contained in:
Máté Kocsis 2023-04-16 22:20:26 +02:00 committed by GitHub
parent 4dad419ae6
commit 414f71a902
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
53 changed files with 1227 additions and 92 deletions

View file

@ -297,7 +297,7 @@ static zval *reflection_instantiate(zend_class_entry *pce, zval *object) /* {{{
static void _const_string(smart_str *str, char *name, zval *value, char *indent);
static void _function_string(smart_str *str, zend_function *fptr, zend_class_entry *scope, char* indent);
static void _property_string(smart_str *str, zend_property_info *prop, const char *prop_name, char* indent);
static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char* indent);
static void _class_const_string(smart_str *str, zend_string *name, zend_class_constant *c, char* indent);
static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char *indent);
static void _extension_string(smart_str *str, zend_module_entry *module, char *indent);
static void _zend_extension_string(smart_str *str, zend_extension *extension, char *indent);
@ -384,7 +384,7 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char
zend_class_constant *c;
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, c) {
_class_const_string(str, ZSTR_VAL(key), c, ZSTR_VAL(sub_indent));
_class_const_string(str, key, c, ZSTR_VAL(sub_indent));
if (UNEXPECTED(EG(exception))) {
zend_string_release(sub_indent);
return;
@ -556,17 +556,18 @@ static void _const_string(smart_str *str, char *name, zval *value, char *indent)
/* }}} */
/* {{{ _class_const_string */
static void _class_const_string(smart_str *str, char *name, zend_class_constant *c, char *indent)
static void _class_const_string(smart_str *str, zend_string *name, zend_class_constant *c, char *indent)
{
if (zval_update_constant_ex(&c->value, c->ce) == FAILURE) {
if (Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, name, c->ce) == FAILURE) {
return;
}
const char *visibility = zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c));
const char *final = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_FINAL ? "final " : "";
const char *type = zend_zval_type_name(&c->value);
zend_string *type_str = ZEND_TYPE_IS_SET(c->type) ? zend_type_to_string(c->type) : NULL;
const char *type = type_str ? ZSTR_VAL(type_str) : zend_zval_type_name(&c->value);
smart_str_append_printf(str, "%sConstant [ %s%s %s %s ] { ",
indent, final, visibility, type, name);
indent, final, visibility, type, ZSTR_VAL(name));
if (Z_TYPE(c->value) == IS_ARRAY) {
smart_str_appends(str, "Array");
} else if (Z_TYPE(c->value) == IS_OBJECT) {
@ -578,6 +579,10 @@ static void _class_const_string(smart_str *str, char *name, zend_class_constant
zend_tmp_string_release(tmp_value_str);
}
smart_str_appends(str, " }\n");
if (type_str) {
zend_string_release(type_str);
}
}
/* }}} */
@ -3796,7 +3801,7 @@ ZEND_METHOD(ReflectionClassConstant, __toString)
ZVAL_DEREF(name);
ZEND_ASSERT(Z_TYPE_P(name) == IS_STRING);
_class_const_string(&str, Z_STRVAL_P(name), ref, "");
_class_const_string(&str, Z_STR_P(name), ref, "");
RETURN_STR(smart_str_extract(&str));
}
/* }}} */
@ -3820,6 +3825,39 @@ ZEND_METHOD(ReflectionClassConstant, getName)
}
/* }}} */
/* Returns the type associated with the class constant */
ZEND_METHOD(ReflectionClassConstant, getType)
{
reflection_object *intern;
zend_class_constant *ref;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
GET_REFLECTION_OBJECT_PTR(ref);
if (!ZEND_TYPE_IS_SET(ref->type)) {
RETURN_NULL();
}
reflection_type_factory(ref->type, return_value, 1);
}
/* Returns whether class constant has a type */
ZEND_METHOD(ReflectionClassConstant, hasType)
{
reflection_object *intern;
zend_class_constant *ref;
if (zend_parse_parameters_none() == FAILURE) {
RETURN_THROWS();
}
GET_REFLECTION_OBJECT_PTR(ref);
RETVAL_BOOL(ZEND_TYPE_IS_SET(ref->type));
}
static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
{
reflection_object *intern;
@ -3887,8 +3925,19 @@ ZEND_METHOD(ReflectionClassConstant, getValue)
}
GET_REFLECTION_OBJECT_PTR(ref);
zval *name = reflection_prop_name(ZEND_THIS);
if (Z_ISUNDEF_P(name)) {
zend_throw_error(NULL,
"Typed property ReflectionClassConstant::$name "
"must not be accessed before initialization");
RETURN_THROWS();
}
if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
zval_update_constant_ex(&ref->value, ref->ce);
zend_result result = zend_update_class_constant(ref, Z_STR_P(name), ref->ce);
if (result == FAILURE) {
RETURN_THROWS();
}
}
ZVAL_COPY_OR_DUP(return_value, &ref->value);
}
@ -4694,7 +4743,7 @@ ZEND_METHOD(ReflectionClass, getConstants)
array_init(return_value);
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), key, constant) {
if (UNEXPECTED(zval_update_constant_ex(&constant->value, constant->ce) != SUCCESS)) {
if (UNEXPECTED(Z_TYPE(constant->value) == IS_CONSTANT_AST && zend_update_class_constant(constant, key, constant->ce) != SUCCESS)) {
RETURN_THROWS();
}
@ -4744,7 +4793,7 @@ ZEND_METHOD(ReflectionClass, getConstant)
zend_class_entry *ce;
HashTable *constants_table;
zend_class_constant *c;
zend_string *name;
zend_string *name, *key;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
RETURN_THROWS();
@ -4752,8 +4801,8 @@ ZEND_METHOD(ReflectionClass, getConstant)
GET_REFLECTION_OBJECT_PTR(ce);
constants_table = CE_CONSTANTS_TABLE(ce);
ZEND_HASH_MAP_FOREACH_PTR(constants_table, c) {
if (UNEXPECTED(zval_update_constant_ex(&c->value, c->ce) != SUCCESS)) {
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(constants_table, key, c) {
if (UNEXPECTED(Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, key, c->ce) != SUCCESS)) {
RETURN_THROWS();
}
} ZEND_HASH_FOREACH_END();
@ -6954,7 +7003,7 @@ ZEND_METHOD(ReflectionEnumBackedCase, getBackingValue)
if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
zval_update_constant_ex(&ref->value, ref->ce);
if (EG(exception)) {
return;
RETURN_THROWS();
}
}