diff --git a/Zend/Optimizer/escape_analysis.c b/Zend/Optimizer/escape_analysis.c index 193479bae4b74..7175f1b435fa2 100644 --- a/Zend/Optimizer/escape_analysis.c +++ b/Zend/Optimizer/escape_analysis.c @@ -20,6 +20,7 @@ #include "Optimizer/zend_optimizer_internal.h" #include "zend_bitset.h" #include "zend_cfg.h" +#include "zend_compile.h" #include "zend_ssa.h" #include "zend_inference.h" #include "zend_dump.h" @@ -162,7 +163,7 @@ static bool is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, i script, op_array, opline); uint32_t forbidden_flags = /* These flags will always cause an exception */ - ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS + ZEND_ACC_STATIC|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT; if (ce && !ce->parent diff --git a/Zend/zend_API.c b/Zend/zend_API.c index f702270dbc117..118dbeaf8565a 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1795,13 +1795,15 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties) * calling zend_merge_properties(). */ static zend_always_inline zend_result _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */ { - if (UNEXPECTED(class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_ENUM))) { + if (UNEXPECTED(class_type->ce_flags & (ZEND_ACC_STATIC|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_ENUM))) { if (class_type->ce_flags & ZEND_ACC_INTERFACE) { zend_throw_error(NULL, "Cannot instantiate interface %s", ZSTR_VAL(class_type->name)); } else if (class_type->ce_flags & ZEND_ACC_TRAIT) { zend_throw_error(NULL, "Cannot instantiate trait %s", ZSTR_VAL(class_type->name)); } else if (class_type->ce_flags & ZEND_ACC_ENUM) { zend_throw_error(NULL, "Cannot instantiate enum %s", ZSTR_VAL(class_type->name)); + } else if (class_type->ce_flags & ZEND_ACC_STATIC) { + zend_throw_error(NULL, "Cannot instantiate static class %s", ZSTR_VAL(class_type->name)); } else { zend_throw_error(NULL, "Cannot instantiate abstract class %s", ZSTR_VAL(class_type->name)); } diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index e6c348ebf21dc..a3058e24b16ae 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1837,6 +1837,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio if (decl->flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) { smart_str_appends(str, "abstract "); } + if (decl->flags & ZEND_ACC_STATIC) { + smart_str_appends(str, "static "); + } if (decl->flags & ZEND_ACC_FINAL) { smart_str_appends(str, "final "); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ed1eb782f5f9e..e7fdc5bb1c8a8 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -926,6 +926,7 @@ uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */ "Multiple abstract modifiers are not allowed", 0); return 0; } + if ((flags & ZEND_ACC_FINAL) && (new_flag & ZEND_ACC_FINAL)) { zend_throw_exception(zend_ce_compile_error, "Multiple final modifiers are not allowed", 0); return 0; @@ -939,6 +940,12 @@ uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */ "Cannot use the final modifier on an abstract class", 0); return 0; } + if ((flags & ZEND_ACC_STATIC) && (new_flag & ZEND_ACC_STATIC)) { + zend_throw_exception(zend_ce_compile_error, + "Multiple static modifiers are not allowed", 0); + return 0; + } + return new_flags; } /* }}} */ @@ -955,6 +962,10 @@ uint32_t zend_add_anonymous_class_modifier(uint32_t flags, uint32_t new_flag) zend_throw_exception(zend_ce_compile_error, "Cannot use the final modifier on an anonymous class", 0); return 0; } + if (new_flag & ZEND_ACC_STATIC) { + zend_throw_exception(zend_ce_compile_error, "Cannot use the static modifier on an anonymous class", 0); + return 0; + } if ((flags & ZEND_ACC_READONLY_CLASS) && (new_flag & ZEND_ACC_READONLY_CLASS)) { zend_throw_exception(zend_ce_compile_error, "Multiple readonly modifiers are not allowed", 0); return 0; @@ -4740,7 +4751,7 @@ static zend_result zend_compile_func_sprintf(znode *result, zend_ast_list *args) char *p; char *end; uint32_t string_placeholder_count; - + string_placeholder_count = 0; p = Z_STRVAL_P(format_string); end = p + Z_STRLEN_P(format_string); @@ -4944,7 +4955,7 @@ static zend_result zend_try_compile_special_func_ex(znode *result, zend_string * } else if (zend_string_equals_literal(lcname, "array_key_exists")) { return zend_compile_func_array_key_exists(result, args); } else if (zend_string_equals_literal(lcname, "sprintf")) { - return zend_compile_func_sprintf(result, args); + return zend_compile_func_sprintf(result, args); } else { return FAILURE; } @@ -8573,7 +8584,7 @@ static void zend_compile_class_decl(znode *result, zend_ast *ast, bool toplevel) /* Reset lineno for final opcodes and errors */ CG(zend_lineno) = ast->lineno; - if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { + if ((ce->ce_flags & (ZEND_ACC_STATIC|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { zend_verify_abstract_class(ce); } diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 748c8a8862791..a85072f33465c 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -617,6 +617,7 @@ class_modifier: T_ABSTRACT { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; } | T_FINAL { $$ = ZEND_ACC_FINAL; } | T_READONLY { $$ = ZEND_ACC_READONLY_CLASS|ZEND_ACC_NO_DYNAMIC_PROPERTIES; } + | T_STATIC { $$ = ZEND_ACC_STATIC; } ; trait_declaration_statement: diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index 1702c8cf9d61e..9e943e85e9a77 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -758,7 +758,7 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags if (ce == NULL) { ce = zend_standard_class_def; } - if (UNEXPECTED(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) { + if (UNEXPECTED(ce->ce_flags & (ZEND_ACC_STATIC|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) { zend_throw_error(NULL, "Class %s cannot be instantiated", ZSTR_VAL(ce->name)); RETURN_THROWS(); } diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index f4386babef876..49da45ebf147d 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -348,6 +348,9 @@ static void _class_string(smart_str *str, zend_class_entry *ce, zval *obj, char if (ce->ce_flags & ZEND_ACC_READONLY_CLASS) { smart_str_append_printf(str, "readonly "); } + if (ce->ce_flags & ZEND_ACC_STATIC) { + smart_str_append_printf(str, "static "); + } smart_str_append_printf(str, "class "); } smart_str_append_printf(str, "%s", ZSTR_VAL(ce->name)); @@ -1575,7 +1578,6 @@ ZEND_METHOD(Reflection, getModifierNames) if (modifiers & ZEND_ACC_FINAL) { add_next_index_stringl(return_value, "final", sizeof("final")-1); } - /* These are mutually exclusive */ switch (modifiers & ZEND_ACC_PPP_MASK) { case ZEND_ACC_PUBLIC: @@ -4934,7 +4936,7 @@ ZEND_METHOD(ReflectionClass, isInstantiable) RETURN_THROWS(); } GET_REFLECTION_OBJECT_PTR(ce); - if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) { + if (ce->ce_flags & (ZEND_ACC_STATIC|ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) { RETURN_FALSE; } @@ -4959,7 +4961,7 @@ ZEND_METHOD(ReflectionClass, isCloneable) RETURN_THROWS(); } GET_REFLECTION_OBJECT_PTR(ce); - if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) { + if (ce->ce_flags & (ZEND_ACC_STATIC|ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) { RETURN_FALSE; } if (!Z_ISUNDEF(intern->obj)) { @@ -5028,7 +5030,7 @@ ZEND_METHOD(ReflectionClass, getModifiers) { reflection_object *intern; zend_class_entry *ce; - uint32_t keep_flags = ZEND_ACC_FINAL | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_READONLY_CLASS; + uint32_t keep_flags = ZEND_ACC_STATIC| ZEND_ACC_FINAL | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_READONLY_CLASS; if (zend_parse_parameters_none() == FAILURE) { RETURN_THROWS(); @@ -5433,7 +5435,7 @@ ZEND_METHOD(ReflectionClass, isIterable) GET_REFLECTION_OBJECT_PTR(ce); - if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | + if (ce->ce_flags & (ZEND_ACC_STATIC| ZEND_ACC_INTERFACE | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { RETURN_FALSE; } diff --git a/ext/reflection/php_reflection.stub.php b/ext/reflection/php_reflection.stub.php index 59f27981d8b20..3c0896e89b1f2 100644 --- a/ext/reflection/php_reflection.stub.php +++ b/ext/reflection/php_reflection.stub.php @@ -249,6 +249,8 @@ class ReflectionClass implements Reflector public const int IS_FINAL = UNKNOWN; /** @cvalue ZEND_ACC_READONLY_CLASS */ public const int IS_READONLY = UNKNOWN; + /** @cvalue ZEND_ACC_STATIC */ + public const int IS_STATIC = UNKNOWN; public string $name; diff --git a/ext/reflection/php_reflection_arginfo.h b/ext/reflection/php_reflection_arginfo.h index 250e91f0926bd..bdf1291b8cea7 100644 --- a/ext/reflection/php_reflection_arginfo.h +++ b/ext/reflection/php_reflection_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 53cb11e3aaa2215f8dbb39778dfbc1bd28f629af */ + * Stub hash: bcb4a31e75b86f5b33e96c10234be82ca7131789 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0) ZEND_ARG_TYPE_INFO(0, modifiers, IS_LONG, 0) @@ -1386,6 +1386,12 @@ static zend_class_entry *register_class_ReflectionClass(zend_class_entry *class_ zend_declare_typed_class_constant(class_entry, const_IS_READONLY_name, &const_IS_READONLY_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release(const_IS_READONLY_name); + zval const_IS_STATIC_value; + ZVAL_LONG(&const_IS_STATIC_value, ZEND_ACC_STATIC); + zend_string *const_IS_STATIC_name = zend_string_init_interned("IS_STATIC", sizeof("IS_STATIC") - 1, 1); + zend_declare_typed_class_constant(class_entry, const_IS_STATIC_name, &const_IS_STATIC_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release(const_IS_STATIC_name); + zval property_name_default_value; ZVAL_UNDEF(&property_name_default_value); zend_string *property_name_name = zend_string_init("name", sizeof("name") - 1, 1); diff --git a/ext/tokenizer/tokenizer.c b/ext/tokenizer/tokenizer.c index 58594cac30782..8b1013be272c5 100644 --- a/ext/tokenizer/tokenizer.c +++ b/ext/tokenizer/tokenizer.c @@ -106,6 +106,10 @@ PHP_METHOD(PhpToken, tokenize) zend_throw_error(NULL, "Cannot instantiate abstract class %s", ZSTR_VAL(token_class->name)); RETURN_THROWS(); } + if (token_class->ce_flags & ZEND_ACC_STATIC) { + zend_throw_error(NULL, "Cannot instantiate static class %s", ZSTR_VAL(token_class->name)); + RETURN_THROWS(); + } if (zend_update_class_constants(token_class) == FAILURE) { RETURN_THROWS(); } diff --git a/main/streams/userspace.c b/main/streams/userspace.c index bce9ed3a6c483..d9bdc0aa7ab38 100644 --- a/main/streams/userspace.c +++ b/main/streams/userspace.c @@ -260,7 +260,7 @@ static zend_result call_method_if_exists( static void user_stream_create_object(struct php_user_stream_wrapper *uwrap, php_stream_context *context, zval *object) { - if (uwrap->ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { + if (uwrap->ce->ce_flags & (ZEND_ACC_STATIC|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { ZVAL_UNDEF(object); return; }