Skip to content

[RFC] Implement static classes #14583

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Zend/Optimizer/escape_analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
3 changes: 3 additions & 0 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ");
}
Expand Down
17 changes: 14 additions & 3 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
/* }}} */
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion ext/mysqli/mysqli.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
12 changes: 7 additions & 5 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
}

Expand All @@ -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)) {
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 2 additions & 0 deletions ext/reflection/php_reflection.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
8 changes: 7 additions & 1 deletion ext/reflection/php_reflection_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions ext/tokenizer/tokenizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down
2 changes: 1 addition & 1 deletion main/streams/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Loading