diff --git a/NEWS b/NEWS index 23212414d361..ca93eb90d640 100644 --- a/NEWS +++ b/NEWS @@ -126,9 +126,8 @@ PHP NEWS - PGSQL: . Enabled 64 bits support for pg_lo_truncate()/pg_lo_tell() if the server supports it. (KentarouTakeda) - . pg_fetch_object() now surfaces non-instantiable class errors - before fetching, resolves the constructor via the get_constructor - handler, and reports the empty-constructor ValueError on the + . pg_fetch_object() now surfaces non-instantiable class errorsv before + fetching, and reports the empty-constructor ValueError on the $constructor_args argument. (David Carlier) - Phar: diff --git a/UPGRADING b/UPGRADING index ffdf738828cf..e7975d333a18 100644 --- a/UPGRADING +++ b/UPGRADING @@ -43,6 +43,10 @@ PHP 8.6 UPGRADE NOTES . MessageFormatter::parse() and parseMessage() now return PHP_INT_MIN as int, rather than float, on 64-bit platforms when parsing integer values. +- MySQLi: + . mysqli_fetch_object() no longer accepts classes with non-public + constructors. + - PCNTL: . pcntl_alarm() now raises a ValueError if the seconds argument is lower than zero or greater than platform's UINT_MAX. @@ -54,6 +58,10 @@ PHP 8.6 UPGRADE NOTES execution error occurs (e.g. malformed UTF-8 input with the /u modifier). This is consistent with other preg_* functions. +- PDO: + . PDOStatement::fetchObject() no longer accepts classes with non-public + constructors. + - Phar: . Phar::mungServer() now raises a ValueError when an invalid argument value is passed instead of being silently ignored. @@ -69,6 +77,8 @@ PHP 8.6 UPGRADE NOTES $constructor_args argument instead of $class. Errors raised when the requested class is not instantiable (abstract, interface, enum) now surface before the row is fetched. + . pg_fetch_object() no longer accepts classes with non-public + constructors. - Posix: . posix_access() now raises a ValueError when an invalid $flags @@ -76,6 +86,10 @@ PHP 8.6 UPGRADE NOTES . posix_mkfifo() now raises a ValueError when an invalid $permissions argument value is passed. +- Reflection: + . ReflectionClass::newInstanceWithoutConstructor() no longer accepts + classes with non-public constructors. + - Session: . Setting session.cookie_path, session.cookie_domain, or session.cache_limiter to a value containing null bytes now emits a warning and leaves the setting diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index c340ba64833c..8cc8abd82615 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -110,6 +110,10 @@ PHP 8.6 INTERNALS UPGRADE NOTES . Added ZEND_CONTAINER_OF(). . The OPENBASEDIR_CHECKPATH() compatibility macro has been removed, instead use php_check_open_basedir() directly. + . The get_constructor object handler has been removed. + Instead to mark an internal class as not instantiable the new + #[\NonInstantiableClass("Reason")] attribute should be attached to the + class definition in the stubs. ======================== 2. Build system changes diff --git a/Zend/Optimizer/escape_analysis.c b/Zend/Optimizer/escape_analysis.c index 8dbd6855d68d..69fcaf35306a 100644 --- a/Zend/Optimizer/escape_analysis.c +++ b/Zend/Optimizer/escape_analysis.c @@ -165,7 +165,6 @@ static bool is_allocation_def(zend_op_array *op_array, zend_ssa *ssa, int def, i if (ce && !ce->parent && !ce->create_object - && ce->default_object_handlers->get_constructor == zend_std_get_constructor && ce->default_object_handlers->dtor_obj == zend_objects_destroy_object && !ce->constructor && !ce->destructor @@ -234,7 +233,6 @@ static bool is_local_def(zend_op_array *op_array, zend_ssa *ssa, int def, int va script, op_array, opline); if (ce && !ce->create_object - && ce->default_object_handlers->get_constructor == zend_std_get_constructor && ce->default_object_handlers->dtor_obj == zend_objects_destroy_object && !ce->constructor && !ce->destructor diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 05d33d3d75fb..fbf7a938ed34 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -3394,8 +3394,7 @@ static zend_always_inline zend_result _zend_update_type_info( /* New objects without constructors cannot escape. */ if (ce && !ce->constructor - && !ce->create_object - && ce->default_object_handlers->get_constructor == zend_std_get_constructor) { + && !ce->create_object) { tmp &= ~MAY_BE_RCN; } UPDATE_SSA_TYPE(tmp, ssa_op->result_def); diff --git a/Zend/tests/closures/closure_instantiate.phpt b/Zend/tests/closures/closure_instantiate.phpt index de3b866cb82e..03d2c45a475d 100644 --- a/Zend/tests/closures/closure_instantiate.phpt +++ b/Zend/tests/closures/closure_instantiate.phpt @@ -8,14 +8,10 @@ Mark Baker mark@lange.demon.co.uk at the PHPNW2017 Conference for PHP Testfest 2 try { // Closures should be instantiatable using new $x = new Closure(); -} catch (Exception $e) { - // Instantiating a closure is an error, not an exception, so we shouldn't see this - echo 'EXCEPTION: ', $e->getMessage(); } catch (Throwable $e) { - // This is the message that we should see for a caught error - echo 'ERROR: ', $e->getMessage(); + echo $e::class, ': ', $e->getMessage(); } ?> --EXPECT-- -ERROR: Instantiation of class Closure is not allowed +Error: Instantiation of class Closure is not allowed diff --git a/Zend/tests/enum/no-new-through-reflection.phpt b/Zend/tests/enum/no-new-through-reflection.phpt index 9a92559cd3d6..fa1e1e23c1bb 100644 --- a/Zend/tests/enum/no-new-through-reflection.phpt +++ b/Zend/tests/enum/no-new-through-reflection.phpt @@ -7,10 +7,10 @@ enum Foo {} try { (new \ReflectionClass(Foo::class))->newInstanceWithoutConstructor(); -} catch (Error $e) { - echo $e->getMessage() . "\n"; +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage() . "\n"; } ?> --EXPECT-- -Cannot instantiate enum Foo +ReflectionException: Cannot instantiate enum Foo diff --git a/Zend/tests/traits/bug60173.phpt b/Zend/tests/traits/bug60173.phpt index be7f652bf93b..120de3fb40d4 100644 --- a/Zend/tests/traits/bug60173.phpt +++ b/Zend/tests/traits/bug60173.phpt @@ -9,7 +9,7 @@ $rc = new ReflectionClass('foo'); $rc->newInstance(); ?> --EXPECTF-- -Fatal error: Uncaught Error: Cannot instantiate trait foo in %s:%d +Fatal error: Uncaught ReflectionException: Cannot instantiate trait foo in %s:%d Stack trace: #0 %s(%d): ReflectionClass->newInstance() #1 {main} diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 65834adbafff..111ca2920327 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -25,6 +25,7 @@ #include "zend_hash.h" #include "zend_modules.h" #include "zend_extensions.h" +#include "zend_attributes.h" #include "zend_constants.h" #include "zend_interfaces.h" #include "zend_exceptions.h" @@ -1792,16 +1793,7 @@ ZEND_API void object_properties_load(zend_object *object, const HashTable *prope 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_UNINSTANTIABLE)) { - 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 { - ZEND_ASSERT(class_type->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)); - zend_throw_error(NULL, "Cannot instantiate abstract class %s", ZSTR_VAL(class_type->name)); - } + zend_cannot_instantiate_class(class_type, NULL); ZVAL_NULL(arg); Z_OBJ_P(arg) = NULL; return FAILURE; @@ -1845,27 +1837,21 @@ ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type) /* ZEND_API zend_result object_init_with_constructor(zval *arg, zend_class_entry *class_type, uint32_t param_count, zval *params, HashTable *named_params) /* {{{ */ { + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(class_type, zend_get_executed_scope()))) { + ZVAL_UNDEF(arg); + return FAILURE; + } + zend_result status = _object_and_properties_init(arg, class_type, NULL); if (UNEXPECTED(status == FAILURE)) { ZVAL_UNDEF(arg); return FAILURE; } zend_object *obj = Z_OBJ_P(arg); - zend_function *constructor = obj->handlers->get_constructor(obj); - if (constructor == NULL) { - /* The constructor can be NULL for 2 different reasons: - * - It is not defined - * - We are not allowed to call the constructor (e.g. private, or internal opaque class) - * and an exception has been thrown - * in the former case, we are (mostly) done and the object is initialized, - * in the latter we need to destroy the object as initialization failed - */ - if (UNEXPECTED(EG(exception))) { - zval_ptr_dtor(arg); - ZVAL_UNDEF(arg); - return FAILURE; - } + zend_function *constructor = class_type->constructor; + /* No constructor, so no need to call it */ + if (constructor == NULL) { /* Surprisingly, this is the only case where internal classes will allow to pass extra arguments * However, if there are named arguments (and it is not empty), * an Error must be thrown to be consistent with new ClassName() */ @@ -1884,6 +1870,7 @@ ZEND_API zend_result object_init_with_constructor(zval *arg, zend_class_entry *c return SUCCESS; } } + /* A constructor should not return a value, however if an exception is thrown * zend_call_known_function() will set the retval to IS_UNDEF */ zval retval; diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index a7e26711cd17..92edea6fdd2f 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1058,6 +1058,10 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( return FAILURE; } + if (!zend_is_class_instantiable(ce)) { + return FAILURE; + } + if (object_init_ex(result, ce) != SUCCESS) { return FAILURE; } @@ -1096,10 +1100,9 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( } } - zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); - if (ctor) { + if (ce->constructor) { zend_call_known_function( - ctor, Z_OBJ_P(result), Z_OBJCE_P(result), NULL, 0, NULL, args); + ce->constructor, Z_OBJ_P(result), Z_OBJCE_P(result), NULL, 0, NULL, args); } zend_array_destroy(args); @@ -1117,10 +1120,9 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( } } - zend_function *ctor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); - if (ctor) { + if (ce->constructor) { zend_call_known_instance_method( - ctor, Z_OBJ_P(result), NULL, args_ast->children, args); + ce->constructor, Z_OBJ_P(result), NULL, args_ast->children, args); } for (uint32_t i = 0; i < args_ast->children; i++) { diff --git a/Zend/zend_attributes.c b/Zend/zend_attributes.c index 71f0d788e921..c477d2d1f9e1 100644 --- a/Zend/zend_attributes.c +++ b/Zend/zend_attributes.c @@ -32,6 +32,7 @@ ZEND_API zend_class_entry *zend_ce_override; ZEND_API zend_class_entry *zend_ce_deprecated; ZEND_API zend_class_entry *zend_ce_nodiscard; ZEND_API zend_class_entry *zend_ce_delayed_target_validation; +ZEND_API zend_class_entry *zend_ce_non_instantiable_class; static zend_object_handlers attributes_object_handlers_sensitive_parameter_value; @@ -264,6 +265,24 @@ ZEND_METHOD(NoDiscard, __construct) } } +ZEND_METHOD(NonInstantiableClass, __construct) +{ + zend_string *message = NULL; + zval value; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(message) + ZEND_PARSE_PARAMETERS_END(); + + ZVAL_STR(&value, message); + zend_update_property_ex(zend_ce_non_instantiable_class, Z_OBJ_P(ZEND_THIS), ZSTR_KNOWN(ZEND_STR_MESSAGE), &value); + + /* The assignment might fail due to 'readonly'. */ + if (UNEXPECTED(EG(exception))) { + RETURN_THROWS(); + } +} + static zend_attribute *get_attribute(const HashTable *attributes, const zend_string *lcname, uint32_t offset) { if (attributes) { @@ -605,6 +624,9 @@ void zend_register_attribute_ce(void) zend_ce_delayed_target_validation = register_class_DelayedTargetValidation(); attr = zend_mark_internal_attribute(zend_ce_delayed_target_validation); + + zend_ce_non_instantiable_class = register_class_NonInstantiableClass(); + attr = zend_mark_internal_attribute(zend_ce_delayed_target_validation); } void zend_attributes_shutdown(void) diff --git a/Zend/zend_attributes.stub.php b/Zend/zend_attributes.stub.php index ded9c89593a3..e6680662dc01 100644 --- a/Zend/zend_attributes.stub.php +++ b/Zend/zend_attributes.stub.php @@ -103,3 +103,13 @@ public function __construct(?string $message = null) {} */ #[Attribute(Attribute::TARGET_ALL)] final class DelayedTargetValidation {} + +/** + * @strict-properties + */ +#[Attribute(Attribute::TARGET_CLASS)] +final class NonInstantiableClass { + public readonly string $message; + + public function __construct(string $message) {} +} diff --git a/Zend/zend_attributes_arginfo.h b/Zend/zend_attributes_arginfo.h index 54a66af29966..a1b177fa3ff7 100644 --- a/Zend/zend_attributes_arginfo.h +++ b/Zend/zend_attributes_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit zend_attributes.stub.php instead. - * Stub hash: b868cb33f41d9442f42d0cec84e33fcc09f5d88c */ + * Stub hash: 674dafdc1e2bdff88a7af7b2c6de13284ec2c445 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Attribute___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, flags, IS_LONG, 0, "Attribute::TARGET_ALL") @@ -33,6 +33,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NoDiscard___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, message, IS_STRING, 1, "null") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_NonInstantiableClass___construct, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, message, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_METHOD(Attribute, __construct); ZEND_METHOD(ReturnTypeWillChange, __construct); ZEND_METHOD(AllowDynamicProperties, __construct); @@ -43,6 +47,7 @@ ZEND_METHOD(SensitiveParameterValue, __debugInfo); ZEND_METHOD(Override, __construct); ZEND_METHOD(Deprecated, __construct); ZEND_METHOD(NoDiscard, __construct); +ZEND_METHOD(NonInstantiableClass, __construct); static const zend_function_entry class_Attribute_methods[] = { ZEND_ME(Attribute, __construct, arginfo_class_Attribute___construct, ZEND_ACC_PUBLIC) @@ -86,6 +91,11 @@ static const zend_function_entry class_NoDiscard_methods[] = { ZEND_FE_END }; +static const zend_function_entry class_NonInstantiableClass_methods[] = { + ZEND_ME(NonInstantiableClass, __construct, arginfo_class_NonInstantiableClass___construct, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static zend_class_entry *register_class_Attribute(void) { zend_class_entry ce, *class_entry; @@ -291,3 +301,22 @@ static zend_class_entry *register_class_DelayedTargetValidation(void) return class_entry; } + +static zend_class_entry *register_class_NonInstantiableClass(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "NonInstantiableClass", class_NonInstantiableClass_methods); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES); + + zval property_message_default_value; + ZVAL_UNDEF(&property_message_default_value); + zend_declare_typed_property(class_entry, ZSTR_KNOWN(ZEND_STR_MESSAGE), &property_message_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); + + zend_string *attribute_name_Attribute_class_NonInstantiableClass_0 = zend_string_init_interned("Attribute", sizeof("Attribute") - 1, true); + zend_attribute *attribute_Attribute_class_NonInstantiableClass_0 = zend_add_class_attribute(class_entry, attribute_name_Attribute_class_NonInstantiableClass_0, 1); + zend_string_release_ex(attribute_name_Attribute_class_NonInstantiableClass_0, true); + ZVAL_LONG(&attribute_Attribute_class_NonInstantiableClass_0->args[0].value, ZEND_ATTRIBUTE_TARGET_CLASS); + + return class_entry; +} diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 840d2dbe32e1..790335f27a2a 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -20,6 +20,7 @@ #include "zend.h" #include "zend_API.h" #include "zend_closures.h" +#include "zend_attributes.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "zend_objects.h" @@ -448,13 +449,6 @@ ZEND_METHOD(Closure, getCurrent) RETURN_OBJ_COPY(obj); } -static ZEND_COLD zend_function *zend_closure_get_constructor(zend_object *object) /* {{{ */ -{ - zend_throw_error(NULL, "Instantiation of class Closure is not allowed"); - return NULL; -} -/* }}} */ - /* int return due to Object Handler API */ static int zend_closure_compare(zval *o1, zval *o2) /* {{{ */ { @@ -736,7 +730,6 @@ void zend_register_closure_ce(void) /* {{{ */ memcpy(&closure_handlers, &std_object_handlers, sizeof(zend_object_handlers)); closure_handlers.free_obj = zend_closure_free_storage; - closure_handlers.get_constructor = zend_closure_get_constructor; closure_handlers.get_method = zend_closure_get_method; closure_handlers.compare = zend_closure_compare; closure_handlers.clone_obj = zend_closure_clone; diff --git a/Zend/zend_closures.stub.php b/Zend/zend_closures.stub.php index 46b51617eef9..f44e10527e3c 100644 --- a/Zend/zend_closures.stub.php +++ b/Zend/zend_closures.stub.php @@ -6,6 +6,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Instantiation of class Closure is not allowed")] final class Closure { private function __construct() {} diff --git a/Zend/zend_closures_arginfo.h b/Zend/zend_closures_arginfo.h index 5bc983a97c2c..9591cee8eb88 100644 --- a/Zend/zend_closures_arginfo.h +++ b/Zend/zend_closures_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit zend_closures.stub.php instead. - * Stub hash: e0626e52adb2d38dad1140c1a28cc7774cc84500 */ + * Stub hash: 95468c1d70556f6ba07327ecc64c396ab4be9206 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Closure___construct, 0, 0, 0) ZEND_END_ARG_INFO() @@ -51,5 +51,13 @@ static zend_class_entry *register_class_Closure(void) INIT_CLASS_ENTRY(ce, "Closure", class_Closure_methods); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Closure_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Closure_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Closure_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Closure_0, true); + zend_string *attribute_NonInstantiableClass_class_Closure_0_arg0_str = zend_string_init("Instantiation of class Closure is not allowed", strlen("Instantiation of class Closure is not allowed"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Closure_0->args[0].value, attribute_NonInstantiableClass_class_Closure_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 105f99d24171..779ef778d721 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -5705,9 +5705,8 @@ static void zend_compile_new(znode *result, zend_ast *ast) /* {{{ */ const zend_function *fbc = NULL; if (ce - && ce->default_object_handlers->get_constructor == zend_std_get_constructor - && ce->constructor - && is_func_accessible(ce->constructor)) { + && ce->constructor + && is_func_accessible(ce->constructor)) { fbc = ce->constructor; } @@ -9530,6 +9529,33 @@ static void zend_compile_enum_backing_type(zend_class_entry *ce, zend_ast *enum_ zend_type_release(type, 0); } +static ZEND_FUNCTION(non_instantiable_constructor) +{ +} + +static zend_arg_info zend_non_instantiable_constructor_arg_info[1] = {0}; +ZEND_API const zend_internal_function zend_non_instantiable_constructor = { + ZEND_INTERNAL_FUNCTION, /* type */ + {0, 0, 0}, /* arg_flags */ + ZEND_ACC_PRIVATE, /* fn_flags */ + NULL, /* name */ + NULL, /* scope */ + NULL, /* prototype */ + 0, /* num_args */ + 0, /* required_num_args */ + zend_non_instantiable_constructor_arg_info + 1, /* arg_info */ + NULL, /* attributes */ + NULL, /* run_time_cache */ + NULL, /* doc_comment */ + 0, /* T */ + 0, /* fn_flags2 */ + NULL, /* prop_info */ + ZEND_FN(non_instantiable_constructor), /* handler */ + NULL, /* module */ + NULL, /* frameless_function_infos */ + {NULL,NULL,NULL,NULL} /* reserved */ +}; + static void zend_compile_class_decl(znode *result, const zend_ast *ast, bool toplevel) /* {{{ */ { const zend_ast_decl *decl = (const zend_ast_decl *) ast; @@ -9651,6 +9677,14 @@ static void zend_compile_class_decl(znode *result, const zend_ast *ast, bool top ce->ce_flags |= ZEND_ACC_TOP_LEVEL; } + /* Add zend_non_instantiable_constructor constructor if class cannot be manually instantiated */ + if (ce->constructor == NULL && (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) == 0) { + const zend_attribute *non_instantiable_class = zend_get_attribute_str(ce->attributes, ZEND_STRL("noninstantiableclass")); + if (non_instantiable_class) { + ce->constructor = (zend_function *) &zend_non_instantiable_constructor; + } + } + /* We currently don't early-bind classes that implement interfaces or use traits */ if (!ce->num_interfaces && !ce->num_traits && !ce->num_hooked_prop_variance_checks #ifdef ZEND_OPCACHE_SHM_REATTACHMENT diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0e31332c97f0..c1717af0d3d7 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -654,6 +654,13 @@ struct _zend_execute_data { zend_array *extra_named_params; }; +/* export zend_non_instantiable_constructor to allow comparisons against it */ +extern ZEND_API const zend_internal_function zend_non_instantiable_constructor; + +static zend_always_inline bool zend_is_non_instantiable_constructor(const zend_function *fn) { + return fn == (const zend_function*) &zend_non_instantiable_constructor; +} + #define ZEND_CALL_HAS_THIS IS_OBJECT_EX /* Top 16 bits of Z_TYPE_INFO(EX(This)) are used as call_info flags */ diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 52d409f2e69b..cfc3973bdeef 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -18,6 +18,7 @@ #include "zend.h" #include "zend_API.h" +#include "zend_attributes.h" #include "zend_hash.h" #include "zend_interfaces.h" #include "zend_exceptions.h" @@ -483,14 +484,6 @@ static zend_object *zend_generator_create(zend_class_entry *class_type) /* {{{ * } /* }}} */ -static ZEND_COLD zend_function *zend_generator_get_constructor(zend_object *object) /* {{{ */ -{ - zend_throw_error(NULL, "The \"Generator\" class is reserved for internal use and cannot be manually instantiated"); - - return NULL; -} -/* }}} */ - ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_data *ptr) { if (!ptr->func && Z_TYPE(ptr->This) == IS_OBJECT) { @@ -1246,7 +1239,6 @@ void zend_register_generator_ce(void) /* {{{ */ zend_generator_handlers.dtor_obj = zend_generator_dtor_storage; zend_generator_handlers.get_gc = zend_generator_get_gc; zend_generator_handlers.clone_obj = NULL; - zend_generator_handlers.get_constructor = zend_generator_get_constructor; zend_ce_ClosedGeneratorException = register_class_ClosedGeneratorException(zend_ce_exception); } diff --git a/Zend/zend_generators.stub.php b/Zend/zend_generators.stub.php index c081d8e35e26..7d1034221c35 100644 --- a/Zend/zend_generators.stub.php +++ b/Zend/zend_generators.stub.php @@ -6,6 +6,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("The \"Generator\" class is reserved for internal use and cannot be manually instantiated")] final class Generator implements Iterator { public function rewind(): void {} diff --git a/Zend/zend_generators_arginfo.h b/Zend/zend_generators_arginfo.h index 6d8d7989c423..7aa4fd28d4e8 100644 --- a/Zend/zend_generators_arginfo.h +++ b/Zend/zend_generators_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit zend_generators.stub.php instead. - * Stub hash: d376e984db0db6ccd9356f632f9d7e1382b2afb7 */ + * Stub hash: 923b63f7385bcb1157ac45d8ff15564e57deb085 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Generator_rewind, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -58,6 +58,14 @@ static zend_class_entry *register_class_Generator(zend_class_entry *class_entry_ class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); zend_class_implements(class_entry, 1, class_entry_Iterator); + zend_string *attribute_name_NonInstantiableClass_class_Generator_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Generator_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Generator_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Generator_0, true); + zend_string *attribute_NonInstantiableClass_class_Generator_0_arg0_str = zend_string_init("The \"Generator\" class is reserved for internal use and cannot be manually instantiated", strlen("The \"Generator\" class is reserved for internal use and cannot be manually instantiated"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Generator_0->args[0].value, attribute_NonInstantiableClass_class_Generator_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index e85b4ea42250..e96955ee3be6 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -195,7 +195,11 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */ return; } - ce->constructor = parent->constructor; + if (zend_is_non_instantiable_constructor(parent->constructor)) { + ce->constructor = NULL; + } else { + ce->constructor = parent->constructor; + } } /* }}} */ diff --git a/Zend/zend_iterators.c b/Zend/zend_iterators.c index c05434486f89..41a2e46ca8e5 100644 --- a/Zend/zend_iterators.c +++ b/Zend/zend_iterators.c @@ -42,7 +42,6 @@ static const zend_object_handlers iterator_object_handlers = { NULL, /* unset dim */ NULL, /* props get */ NULL, /* method get */ - NULL, /* get ctor */ NULL, /* get class name */ NULL, /* cast */ NULL, /* count */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index e7ddd466a51a..62b418e19d96 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -2173,43 +2173,6 @@ ZEND_API ZEND_COLD bool zend_std_unset_static_property(const zend_class_entry *c } /* }}} */ -static ZEND_COLD zend_never_inline void zend_bad_constructor_call(const zend_function *constructor, const zend_class_entry *scope) /* {{{ */ -{ - if (scope) { - zend_throw_error(NULL, "Call to %s %s::__construct() from scope %s", - zend_visibility_string(constructor->common.fn_flags), - ZSTR_VAL(constructor->common.scope->name), - ZSTR_VAL(scope->name) - ); - } else { - zend_throw_error(NULL, "Call to %s %s::__construct() from global scope", - zend_visibility_string(constructor->common.fn_flags), - ZSTR_VAL(constructor->common.scope->name) - ); - } -} -/* }}} */ - -ZEND_API zend_function *zend_std_get_constructor(zend_object *zobj) /* {{{ */ -{ - zend_function *constructor = zobj->ce->constructor; - - if (constructor) { - if (UNEXPECTED(!(constructor->common.fn_flags & ZEND_ACC_PUBLIC))) { - const zend_class_entry *scope = get_fake_or_executed_scope(); - ZEND_ASSERT(!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)); - if (!zend_check_method_accessible(constructor, scope)) { - zend_bad_constructor_call(constructor, scope); - zend_object_store_ctor_failed(zobj); - constructor = NULL; - } - } - } - - return constructor; -} -/* }}} */ - ZEND_API int zend_std_compare_objects(zval *o1, zval *o2) /* {{{ */ { zend_object *zobj1, *zobj2; @@ -2668,7 +2631,6 @@ ZEND_API const zend_object_handlers std_object_handlers = { zend_std_unset_dimension, /* unset_dimension */ zend_std_get_properties, /* get_properties */ zend_std_get_method, /* get_method */ - zend_std_get_constructor, /* get_constructor */ zend_std_get_class_name, /* get_class_name */ zend_std_cast_object_tostring, /* cast_object */ NULL, /* count_elements */ diff --git a/Zend/zend_object_handlers.h b/Zend/zend_object_handlers.h index d0dd804e8a41..24f9d7757a67 100644 --- a/Zend/zend_object_handlers.h +++ b/Zend/zend_object_handlers.h @@ -153,7 +153,6 @@ typedef zend_array *(*zend_object_get_properties_for_t)(zend_object *object, zen /* Andi - EX(fbc) (function being called) needs to be initialized already in the INIT fcall opcode so that the parameters can be parsed the right way. We need to add another callback for this. */ typedef zend_function *(*zend_object_get_method_t)(zend_object **object, zend_string *method, const zval *key); -typedef zend_function *(*zend_object_get_constructor_t)(zend_object *object); /* free_obj should release any resources the object holds, without freeing the * object structure itself. The object does not need to be in a valid state after @@ -221,7 +220,6 @@ struct _zend_object_handlers { zend_object_unset_dimension_t unset_dimension; /* required */ zend_object_get_properties_t get_properties; /* required */ zend_object_get_method_t get_method; /* required */ - zend_object_get_constructor_t get_constructor; /* required */ zend_object_get_class_name_t get_class_name; /* required */ zend_object_cast_t cast_object; /* required */ zend_object_count_elements_t count_elements; /* optional */ @@ -251,7 +249,6 @@ ZEND_API zend_function *zend_std_get_static_method(const zend_class_entry *ce, z ZEND_API zval *zend_std_get_static_property_with_info(zend_class_entry *ce, zend_string *property_name, int type, struct _zend_property_info **prop_info); ZEND_API zval *zend_std_get_static_property(zend_class_entry *ce, zend_string *property_name, int type); ZEND_API ZEND_COLD bool zend_std_unset_static_property(const zend_class_entry *ce, const zend_string *property_name); -ZEND_API zend_function *zend_std_get_constructor(zend_object *object); ZEND_API struct _zend_property_info *zend_get_property_info(const zend_class_entry *ce, zend_string *member, int silent); ZEND_API HashTable *zend_std_get_properties(zend_object *object); ZEND_API HashTable *zend_get_properties_no_lazy_init(zend_object *zobj); diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 537cad8a3644..6c1d8233a0c9 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -19,9 +19,9 @@ #include "zend.h" #include "zend_globals.h" -#include "zend_variables.h" #include "zend_API.h" #include "zend_objects_API.h" +#include "zend_attributes.h" #include "zend_fibers.h" ZEND_API void ZEND_FASTCALL zend_objects_store_init(zend_objects_store *objects, uint32_t init_size) @@ -211,3 +211,70 @@ ZEND_API ZEND_COLD zend_property_info *zend_get_property_info_for_slot_slow(zend } ZEND_HASH_FOREACH_END(); return NULL; } + +ZEND_API ZEND_COLD zend_never_inline void zend_cannot_instantiate_class_ex( + const zend_class_entry *ce, + const zend_class_entry *scope, + zend_class_entry *throwable_ce +) { + if (ce->ce_flags & ZEND_ACC_INTERFACE) { + zend_throw_error(throwable_ce, "Cannot instantiate interface %s", ZSTR_VAL(ce->name)); + return; + } else if (ce->ce_flags & ZEND_ACC_TRAIT) { + zend_throw_error(throwable_ce, "Cannot instantiate trait %s", ZSTR_VAL(ce->name)); + return; + } else if (ce->ce_flags & ZEND_ACC_ENUM) { + zend_throw_error(throwable_ce, "Cannot instantiate enum %s", ZSTR_VAL(ce->name)); + return; + } else if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) { + zend_throw_error(throwable_ce, "Cannot instantiate abstract class %s", ZSTR_VAL(ce->name)); + return; + } + ZEND_ASSERT(ce->constructor); + const zend_function *constructor = ce->constructor; + if (zend_is_non_instantiable_constructor(constructor)) { + const zend_attribute *non_instantiable_class = zend_get_attribute_str(ce->attributes, ZEND_STRL("noninstantiableclass")); + ZEND_ASSERT(non_instantiable_class); + zend_string *msg = Z_STR(non_instantiable_class->args[0].value); + /* Use zend_throw_exception_zstr() when exposed */ + zend_throw_error(throwable_ce, "%s", ZSTR_VAL(msg)); + } else if (scope) { + zend_throw_error(throwable_ce, "Call to %s %s::__construct() from scope %s", + zend_visibility_string(constructor->common.fn_flags), ZSTR_VAL(constructor->common.scope->name), + ZSTR_VAL(scope->name) + ); + } else { + zend_throw_error( + throwable_ce, + "Call to %s %s::__construct() from global scope", + zend_visibility_string(constructor->common.fn_flags), + ZSTR_VAL(constructor->common.scope->name) + ); + } +} + +ZEND_API bool zend_check_class_is_instantiable_or_throw(const zend_class_entry *ce, const zend_class_entry *scope) { + const zend_function *constructor = ce->constructor; + + if (UNEXPECTED(ce->ce_flags & ZEND_ACC_UNINSTANTIABLE)) { + zend_cannot_instantiate_class(ce, scope); + return false; + } + if (constructor) { + /* We cannot rely on the zend_check_method_accessible() call below as the fake non_instantiable_constructor, + * doesn't have a scope, and therefore in the global scope fn->common.scope != scope + * would be false, thus returning that the method is accessible, which is not what we need. */ + if (UNEXPECTED(zend_is_non_instantiable_constructor(constructor))) { + zend_cannot_instantiate_class(ce, NULL); + return false; + } + if (UNEXPECTED(!(constructor->common.fn_flags & ZEND_ACC_PUBLIC))) { + if (!zend_check_method_accessible(constructor, scope)) { + zend_cannot_instantiate_class(ce, scope); + return false; + } + } + } + return true; +} + diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index 694ef398e374..93949d33f590 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -148,4 +148,31 @@ static zend_always_inline bool zend_check_method_accessible(const zend_function return true; } +static inline bool zend_is_class_instantiable(const zend_class_entry *ce) { + return + !(ce->ce_flags & ZEND_ACC_UNINSTANTIABLE) + && (!ce->constructor || ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC) + ; +} +static inline bool zend_is_class_instantiable_ignoring_ctor_visibility(const zend_class_entry *ce) { + return + !(ce->ce_flags & ZEND_ACC_UNINSTANTIABLE) + && (!ce->constructor || !zend_is_non_instantiable_constructor(ce->constructor)) + ; +} + +ZEND_API ZEND_COLD zend_never_inline void zend_cannot_instantiate_class_ex( + const zend_class_entry *ce, + const zend_class_entry *scope, + zend_class_entry *throwable_ce +); +static inline void zend_cannot_instantiate_class( + const zend_class_entry *ce, + const zend_class_entry *scope +) { + zend_cannot_instantiate_class_ex(ce, scope, NULL); +} + +ZEND_API bool zend_check_class_is_instantiable_or_throw(const zend_class_entry *ce, const zend_class_entry *scope); + #endif /* ZEND_OBJECTS_H */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1de7a7cd4195..7e80750bea92 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6002,12 +6002,18 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N } result = EX_VAR(opline->result.var); + const zend_class_entry *scope = EX(func)->op_array.scope; + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(ce, scope))) { + ZVAL_UNDEF(result); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) { ZVAL_UNDEF(result); HANDLE_EXCEPTION(); } - constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); + constructor = ce->constructor; if (constructor == NULL) { /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next * opcode is DO_FCALL in case EXT instructions are used. */ diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5b52f1941845..3fd6e1b214df 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -11395,12 +11395,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_CONS } result = EX_VAR(opline->result.var); + const zend_class_entry *scope = EX(func)->op_array.scope; + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(ce, scope))) { + ZVAL_UNDEF(result); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) { ZVAL_UNDEF(result); HANDLE_EXCEPTION(); } - constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); + constructor = ce->constructor; if (constructor == NULL) { /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next * opcode is DO_FCALL in case EXT instructions are used. */ @@ -30071,12 +30077,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_VAR_ } result = EX_VAR(opline->result.var); + const zend_class_entry *scope = EX(func)->op_array.scope; + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(ce, scope))) { + ZVAL_UNDEF(result); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) { ZVAL_UNDEF(result); HANDLE_EXCEPTION(); } - constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); + constructor = ce->constructor; if (constructor == NULL) { /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next * opcode is DO_FCALL in case EXT instructions are used. */ @@ -37116,12 +37128,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_UNUS } result = EX_VAR(opline->result.var); + const zend_class_entry *scope = EX(func)->op_array.scope; + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(ce, scope))) { + ZVAL_UNDEF(result); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) { ZVAL_UNDEF(result); HANDLE_EXCEPTION(); } - constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); + constructor = ce->constructor; if (constructor == NULL) { /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next * opcode is DO_FCALL in case EXT instructions are used. */ @@ -63967,12 +63985,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_CONST_UNU } result = EX_VAR(opline->result.var); + const zend_class_entry *scope = EX(func)->op_array.scope; + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(ce, scope))) { + ZVAL_UNDEF(result); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) { ZVAL_UNDEF(result); HANDLE_EXCEPTION(); } - constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); + constructor = ce->constructor; if (constructor == NULL) { /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next * opcode is DO_FCALL in case EXT instructions are used. */ @@ -82543,12 +82567,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_VAR_UNUSE } result = EX_VAR(opline->result.var); + const zend_class_entry *scope = EX(func)->op_array.scope; + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(ce, scope))) { + ZVAL_UNDEF(result); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) { ZVAL_UNDEF(result); HANDLE_EXCEPTION(); } - constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); + constructor = ce->constructor; if (constructor == NULL) { /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next * opcode is DO_FCALL in case EXT instructions are used. */ @@ -89588,12 +89618,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_UNUSED_UN } result = EX_VAR(opline->result.var); + const zend_class_entry *scope = EX(func)->op_array.scope; + if (UNEXPECTED(!zend_check_class_is_instantiable_or_throw(ce, scope))) { + ZVAL_UNDEF(result); + HANDLE_EXCEPTION(); + } + if (UNEXPECTED(object_init_ex(result, ce) != SUCCESS)) { ZVAL_UNDEF(result); HANDLE_EXCEPTION(); } - constructor = Z_OBJ_HT_P(result)->get_constructor(Z_OBJ_P(result)); + constructor = ce->constructor; if (constructor == NULL) { /* If there are no arguments, skip over the DO_FCALL opcode. We check if the next * opcode is DO_FCALL in case EXT instructions are used. */ diff --git a/build/gen_stub.php b/build/gen_stub.php index 619c4c905b60..d9fb8ae56626 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -3525,10 +3525,14 @@ function (Name $item) { $declaredStrings = []; + $isInstantiable = true; if (!empty($this->attributes)) { $code .= $php80CondStart; foreach ($this->attributes as $key => $attribute) { + if ($attribute->class === "NonInstantiableClass") { + $isInstantiable = false; + } $code .= $attribute->generateCode( "zend_add_class_attribute(class_entry", "class_{$escapedName}_$key", @@ -3559,6 +3563,10 @@ function (Name $item) { $code .= $php80CondEnd; } + if (!$isInstantiable) { + $code .= "\n\tclass_entry->constructor = (zend_function *) &zend_non_instantiable_constructor;\n"; + } + $code .= "\n\treturn class_entry;\n"; $code .= "}\n"; diff --git a/ext/com_dotnet/com_extension.c b/ext/com_dotnet/com_extension.c index e9c6e46884ce..6a4415e26804 100644 --- a/ext/com_dotnet/com_extension.c +++ b/ext/com_dotnet/com_extension.c @@ -23,6 +23,7 @@ #include "ext/standard/info.h" #include "php_com_dotnet.h" #include "php_com_dotnet_internal.h" +#include "Zend/zend_attributes.h" #include "Zend/zend_exceptions.h" #include "Zend/zend_interfaces.h" diff --git a/ext/com_dotnet/com_extension.stub.php b/ext/com_dotnet/com_extension.stub.php index 0bbe976279f6..3144d01281ed 100644 --- a/ext/com_dotnet/com_extension.stub.php +++ b/ext/com_dotnet/com_extension.stub.php @@ -370,6 +370,7 @@ public function __construct(string $assembly_name, string $datatype_name, int $c } #endif +#[\NonInstantiableClass("Cannot directly construct com_safeproxy_array; it is for internal usage only")] final class com_safearray_proxy { } diff --git a/ext/com_dotnet/com_extension_arginfo.h b/ext/com_dotnet/com_extension_arginfo.h index d0fcf6645717..d5c165a3b42d 100644 --- a/ext/com_dotnet/com_extension_arginfo.h +++ b/ext/com_dotnet/com_extension_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit com_extension.stub.php instead. - * Stub hash: 9b2eea541946c291eb002ee98997f3dcad8bdfce */ + * Stub hash: e61fc06146db8eba3c274b4c9fa2b3202e13528e */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_variant_set, 0, 2, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, variant, variant, 0) @@ -324,6 +324,14 @@ static zend_class_entry *register_class_com_safearray_proxy(void) INIT_CLASS_ENTRY(ce, "com_safearray_proxy", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL); + zend_string *attribute_name_NonInstantiableClass_class_com_safearray_proxy_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_com_safearray_proxy_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_com_safearray_proxy_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_com_safearray_proxy_0, true); + zend_string *attribute_NonInstantiableClass_class_com_safearray_proxy_0_arg0_str = zend_string_init("Cannot directly construct com_safeproxy_array; it is for internal usage only", strlen("Cannot directly construct com_safeproxy_array; it is for internal usage only"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_com_safearray_proxy_0->args[0].value, attribute_NonInstantiableClass_class_com_safearray_proxy_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 81c42da34972..01f966e50cba 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -524,7 +524,6 @@ zend_object_handlers php_com_object_handlers = { com_dimension_delete, com_properties_get, com_method_get, - zend_std_get_constructor, com_class_name_get, com_object_cast, com_object_count, diff --git a/ext/com_dotnet/com_saproxy.c b/ext/com_dotnet/com_saproxy.c index 0317c329589e..c920b3715a93 100644 --- a/ext/com_dotnet/com_saproxy.c +++ b/ext/com_dotnet/com_saproxy.c @@ -321,12 +321,6 @@ static zend_function *saproxy_method_get(zend_object **object, zend_string *name return NULL; } -static zend_function *saproxy_constructor_get(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct com_safeproxy_array; it is for internal usage only"); - return NULL; -} - static zend_string* saproxy_class_name_get(const zend_object *object) { return zend_string_copy(php_com_saproxy_class_entry->name); @@ -412,7 +406,6 @@ zend_object_handlers php_com_saproxy_handlers = { saproxy_dimension_delete, saproxy_properties_get, saproxy_method_get, - saproxy_constructor_get, saproxy_class_name_get, saproxy_object_cast, saproxy_count_elements, diff --git a/ext/curl/curl.stub.php b/ext/curl/curl.stub.php index aadab8cb0b0d..dafc3461f1c5 100644 --- a/ext/curl/curl.stub.php +++ b/ext/curl/curl.stub.php @@ -3711,6 +3711,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct CurlHandle, use curl_init() instead")] final class CurlHandle { } @@ -3719,6 +3720,7 @@ final class CurlHandle * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct CurlMultiHandle, use curl_multi_init() instead")] final class CurlMultiHandle { } @@ -3727,6 +3729,7 @@ final class CurlMultiHandle * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct CurlShareHandle, use curl_share_init() instead")] final class CurlShareHandle { } @@ -3735,6 +3738,7 @@ final class CurlShareHandle * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct CurlSharePersistentHandle, use curl_share_init_persistent() instead")] final class CurlSharePersistentHandle { public readonly array $options; diff --git a/ext/curl/curl_arginfo.h b/ext/curl/curl_arginfo.h index 6fb17ed029e3..b69f915714e2 100644 --- a/ext/curl/curl_arginfo.h +++ b/ext/curl/curl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit curl.stub.php instead. - * Stub hash: 10ebdc94560ed19ecd6b61a11b3dab5d32989d66 */ + * Stub hash: 028c7c273b18c285ba9fa090dcd030f7dd48148f */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_curl_close, 0, 1, IS_VOID, 0) ZEND_ARG_OBJ_INFO(0, handle, CurlHandle, 0) @@ -1014,6 +1014,14 @@ static zend_class_entry *register_class_CurlHandle(void) INIT_CLASS_ENTRY(ce, "CurlHandle", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_CurlHandle_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_CurlHandle_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_CurlHandle_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_CurlHandle_0, true); + zend_string *attribute_NonInstantiableClass_class_CurlHandle_0_arg0_str = zend_string_init("Cannot directly construct CurlHandle, use curl_init() instead", strlen("Cannot directly construct CurlHandle, use curl_init() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_CurlHandle_0->args[0].value, attribute_NonInstantiableClass_class_CurlHandle_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -1024,6 +1032,14 @@ static zend_class_entry *register_class_CurlMultiHandle(void) INIT_CLASS_ENTRY(ce, "CurlMultiHandle", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_CurlMultiHandle_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_CurlMultiHandle_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_CurlMultiHandle_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_CurlMultiHandle_0, true); + zend_string *attribute_NonInstantiableClass_class_CurlMultiHandle_0_arg0_str = zend_string_init("Cannot directly construct CurlMultiHandle, use curl_multi_init() instead", strlen("Cannot directly construct CurlMultiHandle, use curl_multi_init() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_CurlMultiHandle_0->args[0].value, attribute_NonInstantiableClass_class_CurlMultiHandle_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -1034,6 +1050,14 @@ static zend_class_entry *register_class_CurlShareHandle(void) INIT_CLASS_ENTRY(ce, "CurlShareHandle", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_CurlShareHandle_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_CurlShareHandle_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_CurlShareHandle_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_CurlShareHandle_0, true); + zend_string *attribute_NonInstantiableClass_class_CurlShareHandle_0_arg0_str = zend_string_init("Cannot directly construct CurlShareHandle, use curl_share_init() instead", strlen("Cannot directly construct CurlShareHandle, use curl_share_init() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_CurlShareHandle_0->args[0].value, attribute_NonInstantiableClass_class_CurlShareHandle_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -1050,5 +1074,13 @@ static zend_class_entry *register_class_CurlSharePersistentHandle(void) zend_declare_typed_property(class_entry, property_options_name, &property_options_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ARRAY)); zend_string_release_ex(property_options_name, true); + zend_string *attribute_name_NonInstantiableClass_class_CurlSharePersistentHandle_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_CurlSharePersistentHandle_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_CurlSharePersistentHandle_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_CurlSharePersistentHandle_0, true); + zend_string *attribute_NonInstantiableClass_class_CurlSharePersistentHandle_0_arg0_str = zend_string_init("Cannot directly construct CurlSharePersistentHandle, use curl_share_init_persistent() instead", strlen("Cannot directly construct CurlSharePersistentHandle, use curl_share_init_persistent() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_CurlSharePersistentHandle_0->args[0].value, attribute_NonInstantiableClass_class_CurlSharePersistentHandle_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/curl/interface.c b/ext/curl/interface.c index ed544866a886..9ecc1f299997 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -214,7 +214,6 @@ static zend_object_handlers curl_object_handlers; static zend_object *curl_create_object(zend_class_entry *class_type); static void curl_free_obj(zend_object *object); static HashTable *curl_get_gc(zend_object *object, zval **table, int *n); -static zend_function *curl_get_constructor(zend_object *object); static zend_object *curl_clone_obj(zend_object *object); php_curl *init_curl_handle_into_zval(zval *curl); static inline zend_result build_mime_structure_from_hash(php_curl *ch, zval *zpostfields); @@ -360,7 +359,6 @@ PHP_MINIT_FUNCTION(curl) curl_object_handlers.offset = offsetof(php_curl, std); curl_object_handlers.free_obj = curl_free_obj; curl_object_handlers.get_gc = curl_get_gc; - curl_object_handlers.get_constructor = curl_get_constructor; curl_object_handlers.clone_obj = curl_clone_obj; curl_object_handlers.cast_object = curl_cast_object; curl_object_handlers.compare = zend_objects_not_comparable; @@ -391,11 +389,6 @@ static zend_object *curl_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *curl_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct CurlHandle, use curl_init() instead"); - return NULL; -} - static zend_object *curl_clone_obj(zend_object *object) { php_curl *ch; CURL *cp; diff --git a/ext/curl/multi.c b/ext/curl/multi.c index 36ea47a8bca2..f745cbdf721b 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -20,6 +20,7 @@ #include "php.h" #include "Zend/zend_smart_str.h" +#include "zend_attributes.h" #include "curl_private.h" @@ -538,11 +539,6 @@ static zend_object *curl_multi_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *curl_multi_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct CurlMultiHandle, use curl_multi_init() instead"); - return NULL; -} - static void curl_multi_free_obj(zend_object *object) { php_curlm *mh = curl_multi_from_obj(object); @@ -608,7 +604,6 @@ void curl_multi_register_handlers(void) { curl_multi_handlers.offset = offsetof(php_curlm, std); curl_multi_handlers.free_obj = curl_multi_free_obj; curl_multi_handlers.get_gc = curl_multi_get_gc; - curl_multi_handlers.get_constructor = curl_multi_get_constructor; curl_multi_handlers.clone_obj = NULL; curl_multi_handlers.cast_object = curl_cast_object; curl_multi_handlers.compare = zend_objects_not_comparable; diff --git a/ext/curl/share.c b/ext/curl/share.c index 56cd804658a4..b05c2807e8a7 100644 --- a/ext/curl/share.c +++ b/ext/curl/share.c @@ -20,6 +20,7 @@ #include "php.h" #include "Zend/zend_exceptions.h" +#include "zend_attributes.h" #include "curl_private.h" @@ -283,11 +284,6 @@ static zend_object *curl_share_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *curl_share_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct CurlShareHandle, use curl_share_init() instead"); - return NULL; -} - void curl_share_free_obj(zend_object *object) { php_curlsh *sh = curl_share_from_obj(object); @@ -305,7 +301,6 @@ void curl_share_register_handlers(void) { memcpy(&curl_share_handlers, &std_object_handlers, sizeof(zend_object_handlers)); curl_share_handlers.offset = offsetof(php_curlsh, std); curl_share_handlers.free_obj = curl_share_free_obj; - curl_share_handlers.get_constructor = curl_share_get_constructor; curl_share_handlers.clone_obj = NULL; curl_share_handlers.compare = zend_objects_not_comparable; } @@ -314,18 +309,12 @@ void curl_share_register_handlers(void) { static zend_object_handlers curl_share_persistent_handlers; -static zend_function *curl_share_persistent_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct CurlSharePersistentHandle, use curl_share_init_persistent() instead"); - return NULL; -} - void curl_share_persistent_register_handlers(void) { curl_share_persistent_ce->create_object = curl_share_create_object; curl_share_persistent_ce->default_object_handlers = &curl_share_persistent_handlers; memcpy(&curl_share_persistent_handlers, &std_object_handlers, sizeof(zend_object_handlers)); curl_share_persistent_handlers.offset = offsetof(php_curlsh, std); - curl_share_persistent_handlers.get_constructor = curl_share_persistent_get_constructor; curl_share_persistent_handlers.clone_obj = NULL; curl_share_persistent_handlers.compare = zend_objects_not_comparable; } diff --git a/ext/dba/dba.c b/ext/dba/dba.c index 29c560973b77..31811f91b9b8 100644 --- a/ext/dba/dba.c +++ b/ext/dba/dba.c @@ -31,6 +31,7 @@ #include "php_dba.h" #include "ext/standard/info.h" #include "ext/standard/flock_compat.h" /* Compatibility for Windows */ +#include "zend_attributes.h" #include "php_gdbm.h" #include "php_ndbm.h" @@ -316,12 +317,6 @@ static zend_object *dba_connection_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *dba_connection_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct Dba\\Connection, use dba_open() or dba_popen() instead"); - return NULL; -} - static zend_result dba_connection_cast_object(zend_object *obj, zval *result, int type) { if (type == IS_LONG) { @@ -411,7 +406,6 @@ PHP_MINIT_FUNCTION(dba) memcpy(&dba_connection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); dba_connection_object_handlers.offset = offsetof(dba_connection, std); dba_connection_object_handlers.free_obj = dba_connection_free_obj; - dba_connection_object_handlers.get_constructor = dba_connection_get_constructor; dba_connection_object_handlers.clone_obj = NULL; dba_connection_object_handlers.cast_object = dba_connection_cast_object; dba_connection_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/dba/dba.stub.php b/ext/dba/dba.stub.php index ab9758e2c2bb..3d3c01c72192 100644 --- a/ext/dba/dba.stub.php +++ b/ext/dba/dba.stub.php @@ -7,6 +7,7 @@ * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct Dba\\Connection, use dba_open() or dba_popen() instead")] final class Connection { } diff --git a/ext/dba/dba_arginfo.h b/ext/dba/dba_arginfo.h index 22978b68fc7b..8a23461601a4 100644 --- a/ext/dba/dba_arginfo.h +++ b/ext/dba/dba_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit dba.stub.php instead. - * Stub hash: d7ff53b73d3921c41ffd8279ea724bcd3a6d8542 */ + * Stub hash: 6ba636a9b106a1ec8c4332db15f1060efafb886e */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_dba_popen, 0, 2, Dba\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, path, IS_STRING, 0) @@ -110,5 +110,13 @@ static zend_class_entry *register_class_Dba_Connection(void) INIT_NS_CLASS_ENTRY(ce, "Dba", "Connection", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Dba_Connection_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Dba_Connection_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Dba_Connection_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Dba_Connection_0, true); + zend_string *attribute_NonInstantiableClass_class_Dba_Connection_0_arg0_str = zend_string_init("Cannot directly construct Dba\\Connection, use dba_open() or dba_popen() instead", strlen("Cannot directly construct Dba\\Connection, use dba_open() or dba_popen() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Dba_Connection_0->args[0].value, attribute_NonInstantiableClass_class_Dba_Connection_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 779b41fcad3d..7eb9580d043b 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -20,6 +20,7 @@ #include "php_ffi.h" #include "ext/standard/info.h" #include "php_scandir.h" +#include "zend_attributes.h" #include "zend_exceptions.h" #include "zend_closures.h" #include "zend_weakrefs.h" @@ -5123,13 +5124,6 @@ static char *zend_ffi_parse_directives(const char *filename, char *code_pos, cha } /* }}} */ -static ZEND_COLD zend_function *zend_fake_get_constructor(zend_object *object) /* {{{ */ -{ - zend_throw_error(NULL, "Instantiation of %s is not allowed", ZSTR_VAL(object->ce->name)); - return NULL; -} -/* }}} */ - static ZEND_COLD zend_never_inline void zend_bad_array_access(zend_class_entry *ce) /* {{{ */ { zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name)); @@ -5482,7 +5476,6 @@ ZEND_MINIT_FUNCTION(ffi) zend_post_startup_cb = ffi_fixup_temporaries; memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - zend_ffi_handlers.get_constructor = zend_fake_get_constructor; zend_ffi_handlers.free_obj = zend_ffi_free_obj; zend_ffi_handlers.clone_obj = NULL; zend_ffi_handlers.read_property = zend_ffi_read_var; @@ -5508,7 +5501,6 @@ ZEND_MINIT_FUNCTION(ffi) zend_ffi_cdata_ce->get_iterator = zend_ffi_cdata_get_iterator; memcpy(&zend_ffi_cdata_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - zend_ffi_cdata_handlers.get_constructor = zend_fake_get_constructor; zend_ffi_cdata_handlers.free_obj = zend_ffi_cdata_free_obj; zend_ffi_cdata_handlers.clone_obj = zend_ffi_cdata_clone_obj; zend_ffi_cdata_handlers.read_property = zend_ffi_cdata_read_field; @@ -5532,7 +5524,6 @@ ZEND_MINIT_FUNCTION(ffi) zend_ffi_cdata_handlers.get_gc = zend_fake_get_gc; memcpy(&zend_ffi_cdata_value_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - zend_ffi_cdata_value_handlers.get_constructor = zend_fake_get_constructor; zend_ffi_cdata_value_handlers.free_obj = zend_ffi_cdata_free_obj; zend_ffi_cdata_value_handlers.clone_obj = zend_ffi_cdata_clone_obj; zend_ffi_cdata_value_handlers.read_property = zend_ffi_cdata_get; @@ -5555,7 +5546,6 @@ ZEND_MINIT_FUNCTION(ffi) zend_ffi_cdata_value_handlers.get_gc = zend_fake_get_gc; memcpy(&zend_ffi_cdata_free_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - zend_ffi_cdata_free_handlers.get_constructor = zend_fake_get_constructor; zend_ffi_cdata_free_handlers.free_obj = zend_ffi_cdata_free_obj; zend_ffi_cdata_free_handlers.clone_obj = zend_ffi_free_clone_obj; zend_ffi_cdata_free_handlers.read_property = zend_ffi_free_read_property; @@ -5582,7 +5572,6 @@ ZEND_MINIT_FUNCTION(ffi) zend_ffi_ctype_ce->default_object_handlers = &zend_ffi_ctype_handlers; memcpy(&zend_ffi_ctype_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - zend_ffi_ctype_handlers.get_constructor = zend_fake_get_constructor; zend_ffi_ctype_handlers.free_obj = zend_ffi_ctype_free_obj; zend_ffi_ctype_handlers.clone_obj = NULL; zend_ffi_ctype_handlers.read_property = zend_fake_read_property; diff --git a/ext/ffi/ffi.stub.php b/ext/ffi/ffi.stub.php index 3fb9ceee3dfa..07e6cd8d5721 100644 --- a/ext/ffi/ffi.stub.php +++ b/ext/ffi/ffi.stub.php @@ -4,6 +4,7 @@ namespace { /** @not-serializable */ + #[\NonInstantiableClass("Instantiation of FFI is not allowed")] final class FFI { /** @cvalue __BIGGEST_ALIGNMENT__ */ @@ -72,10 +73,12 @@ public static function isNull(FFI\CData $ptr): bool {} namespace FFI { /** @not-serializable */ + #[\NonInstantiableClass("Instantiation of FFI\\CData is not allowed")] final class CData { } /** @not-serializable */ + #[\NonInstantiableClass("Instantiation of FFI\\CType is not allowed")] final class CType { /** @cvalue ZEND_FFI_TYPE_VOID */ public const int TYPE_VOID = UNKNOWN; diff --git a/ext/ffi/ffi_arginfo.h b/ext/ffi/ffi_arginfo.h index a263e0bfb32e..b46cc23b8045 100644 --- a/ext/ffi/ffi_arginfo.h +++ b/ext/ffi/ffi_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit ffi.stub.php instead. - * Stub hash: d3626f5d39317876fc7d4f240b0758f17f3472c8 */ + * Stub hash: 52f9aa63a3b3f307e8d83640e527fe61775799c8 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_FFI_cdef, 0, 0, FFI, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, code, IS_STRING, 0, "\"\"") @@ -209,6 +209,14 @@ static zend_class_entry *register_class_FFI(void) zend_declare_typed_class_constant(class_entry, const___BIGGEST_ALIGNMENT___name, &const___BIGGEST_ALIGNMENT___value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release_ex(const___BIGGEST_ALIGNMENT___name, true); + zend_string *attribute_name_NonInstantiableClass_class_FFI_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_FFI_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_FFI_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_FFI_0, true); + zend_string *attribute_NonInstantiableClass_class_FFI_0_arg0_str = zend_string_init("Instantiation of FFI is not allowed", strlen("Instantiation of FFI is not allowed"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_FFI_0->args[0].value, attribute_NonInstantiableClass_class_FFI_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -219,6 +227,14 @@ static zend_class_entry *register_class_FFI_CData(void) INIT_NS_CLASS_ENTRY(ce, "FFI", "CData", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_FFI_CData_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_FFI_CData_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_FFI_CData_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_FFI_CData_0, true); + zend_string *attribute_NonInstantiableClass_class_FFI_CData_0_arg0_str = zend_string_init("Instantiation of FFI\\CData is not allowed", strlen("Instantiation of FFI\\CData is not allowed"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_FFI_CData_0->args[0].value, attribute_NonInstantiableClass_class_FFI_CData_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -459,6 +475,14 @@ static zend_class_entry *register_class_FFI_CType(void) zend_declare_typed_class_constant(class_entry, const_ABI_VECTORCALL_name, &const_ABI_VECTORCALL_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); zend_string_release_ex(const_ABI_VECTORCALL_name, true); + zend_string *attribute_name_NonInstantiableClass_class_FFI_CType_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_FFI_CType_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_FFI_CType_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_FFI_CType_0, true); + zend_string *attribute_NonInstantiableClass_class_FFI_CType_0_arg0_str = zend_string_init("Instantiation of FFI\\CType is not allowed", strlen("Instantiation of FFI\\CType is not allowed"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_FFI_CType_0->args[0].value, attribute_NonInstantiableClass_class_FFI_CType_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/ftp/ftp.stub.php b/ext/ftp/ftp.stub.php index 6560dd893018..31e2b1593e44 100644 --- a/ext/ftp/ftp.stub.php +++ b/ext/ftp/ftp.stub.php @@ -141,6 +141,7 @@ function ftp_get_option(FTP\Connection $ftp, int $option): int|bool {} * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct FTP\\Connection, use ftp_connect() or ftp_ssl_connect() instead")] final class Connection { } diff --git a/ext/ftp/ftp_arginfo.h b/ext/ftp/ftp_arginfo.h index edb0b4b8a91b..490d061aed50 100644 --- a/ext/ftp/ftp_arginfo.h +++ b/ext/ftp/ftp_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit ftp.stub.php instead. - * Stub hash: 29606d7114a0698b8ae231173a624b17c196ffec */ + * Stub hash: 42ce274f711a6db22d57cf8b1c689846fcb21118 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_ftp_connect, 0, 1, FTP\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, hostname, IS_STRING, 0) @@ -298,5 +298,13 @@ static zend_class_entry *register_class_FTP_Connection(void) INIT_NS_CLASS_ENTRY(ce, "FTP", "Connection", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_FTP_Connection_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_FTP_Connection_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_FTP_Connection_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_FTP_Connection_0, true); + zend_string *attribute_NonInstantiableClass_class_FTP_Connection_0_arg0_str = zend_string_init("Cannot directly construct FTP\\Connection, use ftp_connect() or ftp_ssl_connect() instead", strlen("Cannot directly construct FTP\\Connection, use ftp_connect() or ftp_ssl_connect() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_FTP_Connection_0->args[0].value, attribute_NonInstantiableClass_class_FTP_Connection_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/ftp/php_ftp.c b/ext/ftp/php_ftp.c index 501ce9bc68d7..e2ccd1617d55 100644 --- a/ext/ftp/php_ftp.c +++ b/ext/ftp/php_ftp.c @@ -78,11 +78,6 @@ static zend_object* ftp_object_create(zend_class_entry* ce) { return zobj; } -static zend_function *ftp_object_get_constructor(zend_object *zobj) { - zend_throw_error(NULL, "Cannot directly construct FTP\\Connection, use ftp_connect() or ftp_ssl_connect() instead"); - return NULL; -} - static void ftp_object_destroy(zend_object *zobj) { php_ftp_object *obj = ftp_object_from_zend_object(zobj); @@ -100,7 +95,6 @@ PHP_MINIT_FUNCTION(ftp) memcpy(&ftp_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); ftp_object_handlers.offset = offsetof(php_ftp_object, std); - ftp_object_handlers.get_constructor = ftp_object_get_constructor; ftp_object_handlers.free_obj = ftp_object_destroy; ftp_object_handlers.clone_obj = NULL; diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 92ab74fda575..7d935c89e6c1 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -138,12 +138,6 @@ typedef struct _gd_ext_image_object { static zend_object_handlers php_gd_image_object_handlers; -static zend_function *php_gd_image_object_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "You cannot initialize a GdImage object except through helper functions"); - return NULL; -} - /** * Returns the underlying php_gd_image_object from a zend_object */ @@ -204,7 +198,6 @@ static void php_gd_object_minit_helper(void) memcpy(&php_gd_image_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); php_gd_image_object_handlers.clone_obj = NULL; php_gd_image_object_handlers.free_obj = php_gd_image_object_free; - php_gd_image_object_handlers.get_constructor = php_gd_image_object_get_constructor; php_gd_image_object_handlers.compare = zend_objects_not_comparable; php_gd_image_object_handlers.offset = offsetof(php_gd_image_object, std); } @@ -255,12 +248,6 @@ static void php_gd_font_object_free(zend_object *zobj) zend_object_std_dtor(zobj); } -static zend_function *php_gd_font_object_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "You cannot initialize a GdFont object except through helper functions"); - return NULL; -} - static void php_gd_font_minit_helper(void) { gd_font_ce = register_class_GdFont(); @@ -270,7 +257,6 @@ static void php_gd_font_minit_helper(void) memcpy(&php_gd_font_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); php_gd_font_object_handlers.clone_obj = NULL; php_gd_font_object_handlers.free_obj = php_gd_font_object_free; - php_gd_font_object_handlers.get_constructor = php_gd_font_object_get_constructor; php_gd_font_object_handlers.offset = offsetof(php_gd_font_object, std); } diff --git a/ext/gd/gd.stub.php b/ext/gd/gd.stub.php index 0632724b44f3..83fd850872ef 100644 --- a/ext/gd/gd.stub.php +++ b/ext/gd/gd.stub.php @@ -463,12 +463,14 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct GdImage, use an appropriate image* function instead")] final class GdImage {} /** * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct GdFont, use imageloadfont() instead")] final class GdFont {} /** diff --git a/ext/gd/gd_arginfo.h b/ext/gd/gd_arginfo.h index 6b6327fd682f..8c0d5ff7e825 100644 --- a/ext/gd/gd_arginfo.h +++ b/ext/gd/gd_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit gd.stub.php instead. - * Stub hash: 2cdc0b485d9b62bb9021973d3c8cce0169b21ac0 */ + * Stub hash: 60466cdb1b67fe1d70000f0e5b0a6831f7be973e */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_gd_info, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -940,6 +940,14 @@ static zend_class_entry *register_class_GdImage(void) INIT_CLASS_ENTRY(ce, "GdImage", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_GdImage_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_GdImage_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_GdImage_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_GdImage_0, true); + zend_string *attribute_NonInstantiableClass_class_GdImage_0_arg0_str = zend_string_init("Cannot directly construct GdImage, use an appropriate image* function instead", strlen("Cannot directly construct GdImage, use an appropriate image* function instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_GdImage_0->args[0].value, attribute_NonInstantiableClass_class_GdImage_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -950,5 +958,13 @@ static zend_class_entry *register_class_GdFont(void) INIT_CLASS_ENTRY(ce, "GdFont", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_GdFont_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_GdFont_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_GdFont_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_GdFont_0, true); + zend_string *attribute_NonInstantiableClass_class_GdFont_0_arg0_str = zend_string_init("Cannot directly construct GdFont, use imageloadfont() instead", strlen("Cannot directly construct GdFont, use imageloadfont() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_GdFont_0->args[0].value, attribute_NonInstantiableClass_class_GdFont_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/ldap/ldap.c b/ext/ldap/ldap.c index 77322d2de59f..86c98fb93b83 100644 --- a/ext/ldap/ldap.c +++ b/ext/ldap/ldap.c @@ -115,11 +115,6 @@ static zend_object *ldap_link_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *ldap_link_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct LDAP\\Connection, use ldap_connect() instead"); - return NULL; -} - static void ldap_link_free(ldap_linkdata *ld) { /* We use ldap_destroy rather than ldap_unbind here, because ldap_unbind @@ -162,11 +157,6 @@ static zend_object *ldap_result_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *ldap_result_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct LDAP\\Result, use the dedicated functions instead"); - return NULL; -} - static void ldap_result_free(ldap_resultdata *result) { ldap_msgfree(result->result); @@ -199,11 +189,6 @@ static zend_object *ldap_result_entry_create_object(zend_class_entry *class_type return &intern->std; } -static zend_function *ldap_result_entry_get_constructor(zend_object *obj) { - zend_throw_error(NULL, "Cannot directly construct LDAP\\ResultEntry, use the dedicated functions instead"); - return NULL; -} - static void ldap_result_entry_free_obj(zend_object *obj) { ldap_result_entry *entry = ldap_result_entry_from_obj(obj); @@ -879,7 +864,6 @@ PHP_MINIT_FUNCTION(ldap) memcpy(&ldap_link_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); ldap_link_object_handlers.offset = offsetof(ldap_linkdata, std); ldap_link_object_handlers.free_obj = ldap_link_free_obj; - ldap_link_object_handlers.get_constructor = ldap_link_get_constructor; ldap_link_object_handlers.clone_obj = NULL; ldap_link_object_handlers.compare = zend_objects_not_comparable; @@ -890,7 +874,6 @@ PHP_MINIT_FUNCTION(ldap) memcpy(&ldap_result_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); ldap_result_object_handlers.offset = offsetof(ldap_resultdata, std); ldap_result_object_handlers.free_obj = ldap_result_free_obj; - ldap_result_object_handlers.get_constructor = ldap_result_get_constructor; ldap_result_object_handlers.clone_obj = NULL; ldap_result_object_handlers.compare = zend_objects_not_comparable; @@ -901,7 +884,6 @@ PHP_MINIT_FUNCTION(ldap) memcpy(&ldap_result_entry_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); ldap_result_entry_object_handlers.offset = offsetof(ldap_result_entry, std); ldap_result_entry_object_handlers.free_obj = ldap_result_entry_free_obj; - ldap_result_entry_object_handlers.get_constructor = ldap_result_entry_get_constructor; ldap_result_entry_object_handlers.clone_obj = NULL; ldap_result_entry_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/ldap/ldap.stub.php b/ext/ldap/ldap.stub.php index 52cf3828dba3..5a11c9c28139 100644 --- a/ext/ldap/ldap.stub.php +++ b/ext/ldap/ldap.stub.php @@ -833,6 +833,7 @@ function ldap_parse_exop(LDAP\Connection $ldap, LDAP\Result $result, &$response_ * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct LDAP\\Connection, use ldap_connect() instead")] final class Connection { } @@ -841,6 +842,7 @@ final class Connection * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct LDAP\\Result, use the dedicated functions instead")] final class Result { } @@ -849,6 +851,7 @@ final class Result * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct LDAP\\ResultEntry, use the dedicated functions instead")] final class ResultEntry { } diff --git a/ext/ldap/ldap_arginfo.h b/ext/ldap/ldap_arginfo.h index 8f5e7e34ba32..eb6621a48189 100644 --- a/ext/ldap/ldap_arginfo.h +++ b/ext/ldap/ldap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit ldap.stub.php instead. - * Stub hash: 0dde8fd813f43640dee842c03365d7431858a56d */ + * Stub hash: 908a50f948c3c80ab77a2a6b1541bb533993c1d7 */ #if defined(HAVE_ORALDAP) ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_ldap_connect, 0, 0, LDAP\\Connection, MAY_BE_FALSE) @@ -775,6 +775,14 @@ static zend_class_entry *register_class_LDAP_Connection(void) INIT_NS_CLASS_ENTRY(ce, "LDAP", "Connection", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_LDAP_Connection_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_LDAP_Connection_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_LDAP_Connection_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_LDAP_Connection_0, true); + zend_string *attribute_NonInstantiableClass_class_LDAP_Connection_0_arg0_str = zend_string_init("Cannot directly construct LDAP\\Connection, use ldap_connect() instead", strlen("Cannot directly construct LDAP\\Connection, use ldap_connect() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_LDAP_Connection_0->args[0].value, attribute_NonInstantiableClass_class_LDAP_Connection_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -785,6 +793,14 @@ static zend_class_entry *register_class_LDAP_Result(void) INIT_NS_CLASS_ENTRY(ce, "LDAP", "Result", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_LDAP_Result_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_LDAP_Result_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_LDAP_Result_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_LDAP_Result_0, true); + zend_string *attribute_NonInstantiableClass_class_LDAP_Result_0_arg0_str = zend_string_init("Cannot directly construct LDAP\\Result, use the dedicated functions instead", strlen("Cannot directly construct LDAP\\Result, use the dedicated functions instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_LDAP_Result_0->args[0].value, attribute_NonInstantiableClass_class_LDAP_Result_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -795,5 +811,13 @@ static zend_class_entry *register_class_LDAP_ResultEntry(void) INIT_NS_CLASS_ENTRY(ce, "LDAP", "ResultEntry", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_LDAP_ResultEntry_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_LDAP_ResultEntry_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_LDAP_ResultEntry_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_LDAP_ResultEntry_0, true); + zend_string *attribute_NonInstantiableClass_class_LDAP_ResultEntry_0_arg0_str = zend_string_init("Cannot directly construct LDAP\\ResultEntry, use the dedicated functions instead", strlen("Cannot directly construct LDAP\\ResultEntry, use the dedicated functions instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_LDAP_ResultEntry_0->args[0].value, attribute_NonInstantiableClass_class_LDAP_ResultEntry_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index b45e7416c773..980ba64049fc 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -14,6 +14,7 @@ +----------------------------------------------------------------------+ */ +#include "../../Zend/zend_compile.h" #ifdef HAVE_CONFIG_H #include #endif @@ -760,8 +761,15 @@ 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))) { - zend_throw_error(NULL, "Class %s cannot be instantiated", ZSTR_VAL(ce->name)); + if (UNEXPECTED(!zend_is_class_instantiable(ce))) { + zend_argument_value_error(ERROR_ARG_POS(2), "Class \"%s\" cannot be instantiated", ZSTR_VAL(ce->name)); + RETURN_THROWS(); + } + if (!ce->constructor && ctor_params && zend_hash_num_elements(ctor_params) > 0) { + zend_argument_value_error(ERROR_ARG_POS(3), + "must be empty when the specified class (%s) does not have a constructor", + ZSTR_VAL(ce->name) + ); RETURN_THROWS(); } fetchtype = MYSQLI_ASSOC; @@ -805,11 +813,6 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags if (ce->constructor) { zend_call_known_function(ce->constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), /* retval */ NULL, /* argc */ 0, /* params */ NULL, ctor_params); - } else if (ctor_params && zend_hash_num_elements(ctor_params) > 0) { - zend_argument_value_error(ERROR_ARG_POS(3), - "must be empty when the specified class (%s) does not have a constructor", - ZSTR_VAL(ce->name) - ); } } } diff --git a/ext/mysqli/tests/bug74968.phpt b/ext/mysqli/tests/bug74968.phpt index 851e2922682d..e87450dacbe6 100644 --- a/ext/mysqli/tests/bug74968.phpt +++ b/ext/mysqli/tests/bug74968.phpt @@ -18,7 +18,7 @@ require_once 'skipifconnectfailure.inc'; ?> ==DONE== --EXPECTF-- -Fatal error: Uncaught Error: Class test cannot be instantiated in %sbug74968.php:%d +Fatal error: Uncaught ValueError: mysqli_result::fetch_object(): Argument #1 ($class) Class "test" cannot be instantiated in %sbug74968.php:%d Stack trace: #0 %sbug74968.php(%d): mysqli_result->fetch_object('test') #1 {main} diff --git a/ext/mysqli/tests/mysqli_fetch_object.phpt b/ext/mysqli/tests/mysqli_fetch_object.phpt index 28e945db52f6..6a57dd0c1ab3 100644 --- a/ext/mysqli/tests/mysqli_fetch_object.phpt +++ b/ext/mysqli/tests/mysqli_fetch_object.phpt @@ -116,14 +116,13 @@ require_once 'skipifconnectfailure.inc'; $this->b = $b; } } - /* - TODO - I think we should bail out here. The following line will give a Fatal error: Call to private ... from invalid context - var_dump($obj = new mysqli_fetch_object_private_constructor(1, 2)); - This does not fail. - */ - mysqli_fetch_object($res, 'mysqli_fetch_object_private_constructor', array('a', 'b')); - mysqli_free_result($res); + + try { + var_dump(mysqli_fetch_object($res, 'mysqli_fetch_object_private_constructor', ['a', 'b'])); + mysqli_free_result($res); + } catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), "\n"; + } try { var_dump(mysqli_fetch_object($res, 'this_class_does_not_exist')); @@ -146,5 +145,6 @@ NULL NULL mysqli_result object is already closed TypeError: mysqli_fetch_object(): Argument #3 ($constructor_args) must be of type array, string given +ValueError: mysqli_fetch_object(): Argument #2 ($class) Class "mysqli_fetch_object_private_constructor" cannot be instantiated TypeError: mysqli_fetch_object(): Argument #2 ($class) must be a valid class name, this_class_does_not_exist given done! diff --git a/ext/odbc/odbc.stub.php b/ext/odbc/odbc.stub.php index f88a71154f8f..062f823a41d2 100644 --- a/ext/odbc/odbc.stub.php +++ b/ext/odbc/odbc.stub.php @@ -7,6 +7,7 @@ * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct Odbc\\Connection, use odbc_connect() or odbc_pconnect() instead")] class Connection { } @@ -15,6 +16,7 @@ class Connection * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct Odbc\\Result, use an appropriate odbc_* function instead")] class Result { } diff --git a/ext/odbc/odbc_arginfo.h b/ext/odbc/odbc_arginfo.h index badd1400148d..612f68d06d64 100644 --- a/ext/odbc/odbc_arginfo.h +++ b/ext/odbc/odbc_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit odbc.stub.php instead. - * Stub hash: f9ba28767b256dbcea087a65aa4bb5f5b509d6f3 */ + * Stub hash: 7b35a7bbf36fdec269eebb54afe46bdfd6a0cc3b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_odbc_close_all, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -408,6 +408,14 @@ static zend_class_entry *register_class_Odbc_Connection(void) INIT_NS_CLASS_ENTRY(ce, "Odbc", "Connection", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Odbc_Connection_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Odbc_Connection_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Odbc_Connection_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Odbc_Connection_0, true); + zend_string *attribute_NonInstantiableClass_class_Odbc_Connection_0_arg0_str = zend_string_init("Cannot directly construct Odbc\\Connection, use odbc_connect() or odbc_pconnect() instead", strlen("Cannot directly construct Odbc\\Connection, use odbc_connect() or odbc_pconnect() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Odbc_Connection_0->args[0].value, attribute_NonInstantiableClass_class_Odbc_Connection_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -418,5 +426,13 @@ static zend_class_entry *register_class_Odbc_Result(void) INIT_NS_CLASS_ENTRY(ce, "Odbc", "Result", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Odbc_Result_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Odbc_Result_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Odbc_Result_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Odbc_Result_0, true); + zend_string *attribute_NonInstantiableClass_class_Odbc_Result_0_arg0_str = zend_string_init("Cannot directly construct Odbc\\Result, use an appropriate odbc_* function instead", strlen("Cannot directly construct Odbc\\Result, use an appropriate odbc_* function instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Odbc_Result_0->args[0].value, attribute_NonInstantiableClass_class_Odbc_Result_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/odbc/php_odbc.c b/ext/odbc/php_odbc.c index 45d30f13a56f..a67d916148e0 100644 --- a/ext/odbc/php_odbc.c +++ b/ext/odbc/php_odbc.c @@ -174,12 +174,6 @@ static zend_object *odbc_connection_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *odbc_connection_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct Odbc\\Connection, use odbc_connect() or odbc_pconnect() instead"); - return NULL; -} - static zend_result odbc_connection_cast_object(zend_object *obj, zval *result, int type) { if (type == IS_LONG) { @@ -217,12 +211,6 @@ static zend_object *odbc_result_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *odbc_result_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct Odbc\\Result, use an appropriate odbc_* function instead"); - return NULL; -} - static zend_result odbc_result_cast_object(zend_object *obj, zval *result, int type) { if (type == IS_LONG) { @@ -509,7 +497,6 @@ PHP_MINIT_FUNCTION(odbc) memcpy(&odbc_connection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); odbc_connection_object_handlers.offset = offsetof(odbc_link, std); odbc_connection_object_handlers.free_obj = odbc_connection_free_obj; - odbc_connection_object_handlers.get_constructor = odbc_connection_get_constructor; odbc_connection_object_handlers.clone_obj = NULL; odbc_connection_object_handlers.cast_object = odbc_connection_cast_object; odbc_connection_object_handlers.compare = zend_objects_not_comparable; @@ -521,7 +508,6 @@ PHP_MINIT_FUNCTION(odbc) memcpy(&odbc_result_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); odbc_result_object_handlers.offset = offsetof(odbc_result, std); odbc_result_object_handlers.free_obj = odbc_result_free_obj; - odbc_result_object_handlers.get_constructor = odbc_result_get_constructor; odbc_result_object_handlers.clone_obj = NULL; odbc_result_object_handlers.cast_object = odbc_result_cast_object; odbc_result_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/opcache/zend_file_cache.c b/ext/opcache/zend_file_cache.c index af59b9b2c34a..9bf8ee18897d 100644 --- a/ext/opcache/zend_file_cache.c +++ b/ext/opcache/zend_file_cache.c @@ -929,7 +929,9 @@ static void zend_file_cache_serialize_class(zval *zv, } } - SERIALIZE_PTR(ce->constructor); + if (ce->constructor && !zend_is_non_instantiable_constructor(ce->constructor)) { + SERIALIZE_PTR(ce->constructor); + } SERIALIZE_PTR(ce->destructor); SERIALIZE_PTR(ce->clone); SERIALIZE_PTR(ce->__get); @@ -1805,6 +1807,12 @@ static void zend_file_cache_unserialize_class(zval *zv, } UNSERIALIZE_PTR(ce->constructor); + if (ce->constructor == NULL && (ce->ce_flags & (ZEND_ACC_ENUM|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) == 0) { + zend_attribute *non_instantiable_class = zend_get_attribute_str(ce->attributes, ZEND_STRL("noninstantiableclass")); + if (non_instantiable_class) { + ce->constructor = (zend_function *) &zend_non_instantiable_constructor;; + } + } UNSERIALIZE_PTR(ce->destructor); UNSERIALIZE_PTR(ce->clone); UNSERIALIZE_PTR(ce->__get); diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 65e63265dfc6..2114b15f4224 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -80,11 +80,6 @@ static zend_object *php_openssl_certificate_create_object(zend_class_entry *clas return &intern->std; } -static zend_function *php_openssl_certificate_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct OpenSSLCertificate, use openssl_x509_read() instead"); - return NULL; -} - static void php_openssl_certificate_free_obj(zend_object *object) { php_openssl_certificate_object *x509_object = php_openssl_certificate_from_obj(object); @@ -113,11 +108,6 @@ static zend_object *php_openssl_request_create_object(zend_class_entry *class_ty return &intern->std; } -static zend_function *php_openssl_request_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct OpenSSLCertificateSigningRequest, use openssl_csr_new() instead"); - return NULL; -} - static void php_openssl_request_free_obj(zend_object *object) { php_openssl_request_object *x509_request = php_openssl_request_from_obj(object); @@ -155,12 +145,6 @@ static zend_object *php_openssl_pkey_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *php_openssl_pkey_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct OpenSSLAsymmetricKey, use openssl_pkey_new() instead"); - return NULL; -} - static void php_openssl_pkey_free_obj(zend_object *object) { php_openssl_pkey_object *key_object = php_openssl_pkey_from_obj(object); @@ -279,13 +263,6 @@ static zend_object *php_openssl_session_create_object(zend_class_entry *class_ty return &intern->std; } -static zend_function *php_openssl_session_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, - "Cannot directly construct OpenSSLSession, use OpenSSLSession::import() or TLS session callbacks"); - return NULL; -} - static void php_openssl_session_free_obj(zend_object *object) { php_openssl_session_object *session_object = php_openssl_session_from_obj(object); @@ -759,7 +736,6 @@ PHP_MINIT_FUNCTION(openssl) memcpy(&php_openssl_certificate_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); php_openssl_certificate_object_handlers.offset = offsetof(php_openssl_certificate_object, std); php_openssl_certificate_object_handlers.free_obj = php_openssl_certificate_free_obj; - php_openssl_certificate_object_handlers.get_constructor = php_openssl_certificate_get_constructor; php_openssl_certificate_object_handlers.clone_obj = NULL; php_openssl_certificate_object_handlers.compare = zend_objects_not_comparable; @@ -770,7 +746,6 @@ PHP_MINIT_FUNCTION(openssl) memcpy(&php_openssl_request_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); php_openssl_request_object_handlers.offset = offsetof(php_openssl_request_object, std); php_openssl_request_object_handlers.free_obj = php_openssl_request_free_obj; - php_openssl_request_object_handlers.get_constructor = php_openssl_request_get_constructor; php_openssl_request_object_handlers.clone_obj = NULL; php_openssl_request_object_handlers.compare = zend_objects_not_comparable; @@ -781,7 +756,6 @@ PHP_MINIT_FUNCTION(openssl) memcpy(&php_openssl_pkey_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); php_openssl_pkey_object_handlers.offset = offsetof(php_openssl_pkey_object, std); php_openssl_pkey_object_handlers.free_obj = php_openssl_pkey_free_obj; - php_openssl_pkey_object_handlers.get_constructor = php_openssl_pkey_get_constructor; php_openssl_pkey_object_handlers.clone_obj = NULL; php_openssl_pkey_object_handlers.compare = zend_objects_not_comparable; @@ -797,7 +771,6 @@ PHP_MINIT_FUNCTION(openssl) memcpy(&php_openssl_session_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); php_openssl_session_object_handlers.offset = offsetof(php_openssl_session_object, std); php_openssl_session_object_handlers.free_obj = php_openssl_session_free_obj; - php_openssl_session_object_handlers.get_constructor = php_openssl_session_get_constructor; php_openssl_session_object_handlers.clone_obj = NULL; php_openssl_session_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/openssl/openssl.stub.php b/ext/openssl/openssl.stub.php index 6080ac323903..abb230818e41 100644 --- a/ext/openssl/openssl.stub.php +++ b/ext/openssl/openssl.stub.php @@ -32,6 +32,7 @@ public function __construct(string $psk, ?string $identity = null) {} /** * @strict-properties */ + #[\NonInstantiableClass("Cannot directly construct Openssl\\Session, use Openssl\\Session::import() or TLS session callbacks")] final class Session { public readonly string $id; @@ -474,6 +475,7 @@ public function __unserialize(array $data): void {} * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct OpenSSLCertificate, use openssl_x509_read() instead")] final class OpenSSLCertificate { } @@ -482,6 +484,7 @@ final class OpenSSLCertificate * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct OpenSSLCertificateSigningRequest, use openssl_csr_new() instead")] final class OpenSSLCertificateSigningRequest { } @@ -490,6 +493,7 @@ final class OpenSSLCertificateSigningRequest * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct OpenSSLAsymmetricKey, use openssl_pkey_new() instead")] final class OpenSSLAsymmetricKey { } diff --git a/ext/openssl/openssl_arginfo.h b/ext/openssl/openssl_arginfo.h index caf47a256e78..8eb9cdb19470 100644 --- a/ext/openssl/openssl_arginfo.h +++ b/ext/openssl/openssl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit openssl.stub.php instead. - * Stub hash: 4d38e81a2f73bb6dd4bbe7a3e0b8ba86600654e2 */ + * Stub hash: 0058ec2ddd8cd5ce2229ef7cec6a72264a63ed54 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_openssl_x509_export_to_file, 0, 2, _IS_BOOL, 0) ZEND_ARG_OBJ_TYPE_MASK(0, certificate, OpenSSLCertificate, MAY_BE_STRING, NULL) @@ -878,6 +878,14 @@ static zend_class_entry *register_class_Openssl_Session(void) zend_declare_typed_property(class_entry, property_id_name, &property_id_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release_ex(property_id_name, true); + zend_string *attribute_name_NonInstantiableClass_class_Openssl_Session_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Openssl_Session_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Openssl_Session_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Openssl_Session_0, true); + zend_string *attribute_NonInstantiableClass_class_Openssl_Session_0_arg0_str = zend_string_init("Cannot directly construct Openssl\\Session, use Openssl\\Session::import() or TLS session callbacks", strlen("Cannot directly construct Openssl\\Session, use Openssl\\Session::import() or TLS session callbacks"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Openssl_Session_0->args[0].value, attribute_NonInstantiableClass_class_Openssl_Session_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -888,6 +896,14 @@ static zend_class_entry *register_class_OpenSSLCertificate(void) INIT_CLASS_ENTRY(ce, "OpenSSLCertificate", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_OpenSSLCertificate_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_OpenSSLCertificate_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_OpenSSLCertificate_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_OpenSSLCertificate_0, true); + zend_string *attribute_NonInstantiableClass_class_OpenSSLCertificate_0_arg0_str = zend_string_init("Cannot directly construct OpenSSLCertificate, use openssl_x509_read() instead", strlen("Cannot directly construct OpenSSLCertificate, use openssl_x509_read() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_OpenSSLCertificate_0->args[0].value, attribute_NonInstantiableClass_class_OpenSSLCertificate_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -898,6 +914,14 @@ static zend_class_entry *register_class_OpenSSLCertificateSigningRequest(void) INIT_CLASS_ENTRY(ce, "OpenSSLCertificateSigningRequest", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_OpenSSLCertificateSigningRequest_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_OpenSSLCertificateSigningRequest_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_OpenSSLCertificateSigningRequest_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_OpenSSLCertificateSigningRequest_0, true); + zend_string *attribute_NonInstantiableClass_class_OpenSSLCertificateSigningRequest_0_arg0_str = zend_string_init("Cannot directly construct OpenSSLCertificateSigningRequest, use openssl_csr_new() instead", strlen("Cannot directly construct OpenSSLCertificateSigningRequest, use openssl_csr_new() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_OpenSSLCertificateSigningRequest_0->args[0].value, attribute_NonInstantiableClass_class_OpenSSLCertificateSigningRequest_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -908,5 +932,13 @@ static zend_class_entry *register_class_OpenSSLAsymmetricKey(void) INIT_CLASS_ENTRY(ce, "OpenSSLAsymmetricKey", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_OpenSSLAsymmetricKey_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_OpenSSLAsymmetricKey_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_OpenSSLAsymmetricKey_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_OpenSSLAsymmetricKey_0, true); + zend_string *attribute_NonInstantiableClass_class_OpenSSLAsymmetricKey_0_arg0_str = zend_string_init("Cannot directly construct OpenSSLAsymmetricKey, use openssl_pkey_new() instead", strlen("Cannot directly construct OpenSSLAsymmetricKey, use openssl_pkey_new() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_OpenSSLAsymmetricKey_0->args[0].value, attribute_NonInstantiableClass_class_OpenSSLAsymmetricKey_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 6a47ec30c862..6af8bcb65372 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -626,6 +626,11 @@ PHP_METHOD(PDO, prepare) zend_type_error("PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement"); RETURN_THROWS(); } + if (UNEXPECTED(!zend_is_class_instantiable_ignoring_ctor_visibility(dbstmt_ce))) { + zend_cannot_instantiate_class(dbstmt_ce, NULL); + RETURN_THROWS(); + } + /* Ignore default constructor as it will always be public */ if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) { zend_type_error("User-supplied statement class cannot have a public constructor"); RETURN_THROWS(); @@ -922,6 +927,11 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value, u zend_argument_type_error(value_arg_num, "PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement"); return false; } + if (UNEXPECTED(!zend_is_class_instantiable_ignoring_ctor_visibility(pce))) { + zend_cannot_instantiate_class(pce, NULL); + return false; + } + /* Ignore default constructor as it will always be public */ if (pce->constructor && !(pce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) { zend_argument_type_error(value_arg_num, "User-supplied statement class cannot have a public constructor"); return false; diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 2b4e5a8f8239..f5b184942312 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -27,6 +27,7 @@ #include "php_pdo.h" #include "php_pdo_driver.h" #include "php_pdo_int.h" +#include "zend_attributes.h" #include "zend_exceptions.h" #include "zend_interfaces.h" #include "php_memory_streams.h" @@ -1087,6 +1088,11 @@ PHP_METHOD(PDOStatement, fetchObject) ce = zend_standard_class_def; } + if (UNEXPECTED(!zend_is_class_instantiable_ignoring_ctor_visibility(ce))) { + zend_argument_value_error(1, "Class \"%s\" cannot be instantiated", ZSTR_VAL(ce->name)); + RETURN_THROWS(); + } + if (ctor_args && zend_hash_num_elements(ctor_args) && ce->constructor == NULL) { zend_argument_value_error(2, "must be empty when class provided in argument #1 ($class) does not have a constructor"); RETURN_THROWS(); @@ -1190,6 +1196,10 @@ PHP_METHOD(PDOStatement, fetchAll) } else { fetch_class = zend_standard_class_def; } + if (UNEXPECTED(!zend_is_class_instantiable_ignoring_ctor_visibility(fetch_class))) { + zend_throw_error(NULL, "Cannot instantiate an object of class %s", ZSTR_VAL(fetch_class->name)); + RETURN_THROWS(); + } if (ctor_args && zend_hash_num_elements(ctor_args) > 0) { if (fetch_class->constructor == NULL) { @@ -1706,6 +1716,10 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a zend_argument_type_error(arg1_arg_num, "must be a valid class"); return false; } + if (UNEXPECTED(!zend_is_class_instantiable_ignoring_ctor_visibility(cep))) { + zend_throw_error(NULL, "Cannot instantiate an object of class %s", ZSTR_VAL(cep->name)); + return false; + } /* Verify constructor_args (args[1]) is ?array */ /* TODO: Improve logic? */ if (variadic_num_args == 2) { @@ -1715,7 +1729,7 @@ bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_a return false; } if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) { - if (cep->constructor == NULL) { + if (UNEXPECTED(cep->constructor == NULL)) { zend_argument_value_error(3, "must be empty when class provided in argument #2 ($class) does not have a constructor"); return false; } @@ -2375,12 +2389,6 @@ static HashTable *row_get_properties_for(zend_object *object, zend_prop_purpose return props; } -static zend_function *row_get_ctor(zend_object *object) -{ - zend_throw_exception_ex(php_pdo_get_exception(), 0, "You may not create a PDORow manually"); - return NULL; -} - static zval *pdo_row_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot) { ZEND_IGNORE_VALUE(object); @@ -2447,6 +2455,5 @@ void pdo_stmt_init(void) pdo_row_object_handlers.has_dimension = row_dim_exists; pdo_row_object_handlers.unset_dimension = row_dim_delete; pdo_row_object_handlers.get_properties_for = row_get_properties_for; - pdo_row_object_handlers.get_constructor = row_get_ctor; pdo_row_object_handlers.compare = zend_objects_not_comparable; } diff --git a/ext/pdo/pdo_stmt.stub.php b/ext/pdo/pdo_stmt.stub.php index b5783d72684a..ffde6c0d148f 100644 --- a/ext/pdo/pdo_stmt.stub.php +++ b/ext/pdo/pdo_stmt.stub.php @@ -68,6 +68,7 @@ public function getIterator(): Iterator {} } /** @not-serializable */ +#[\NonInstantiableClass("A PDORow class cannot be manually instantiated")] final class PDORow { public string $queryString; diff --git a/ext/pdo/pdo_stmt_arginfo.h b/ext/pdo/pdo_stmt_arginfo.h index 080202f897bc..e2df00cea1d7 100644 --- a/ext/pdo/pdo_stmt_arginfo.h +++ b/ext/pdo/pdo_stmt_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit pdo_stmt.stub.php instead. - * Stub hash: 6a5b332ba4bfeceaca6aad734d38dabb66d82c97 */ + * Stub hash: f40ef0875271b733d862d5c0e3b23523428f2ff7 */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_PDOStatement_bindColumn, 0, 2, _IS_BOOL, 0) ZEND_ARG_TYPE_MASK(0, column, MAY_BE_STRING|MAY_BE_LONG, NULL) @@ -162,5 +162,13 @@ static zend_class_entry *register_class_PDORow(void) zend_declare_typed_property(class_entry, property_queryString_name, &property_queryString_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING)); zend_string_release_ex(property_queryString_name, true); + zend_string *attribute_name_NonInstantiableClass_class_PDORow_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_PDORow_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_PDORow_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_PDORow_0, true); + zend_string *attribute_NonInstantiableClass_class_PDORow_0_arg0_str = zend_string_init("A PDORow class cannot be manually instantiated", strlen("A PDORow class cannot be manually instantiated"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_PDORow_0->args[0].value, attribute_NonInstantiableClass_class_PDORow_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/pdo/tests/attr_statement_class/pdo_ATTR_STATEMENT_CLASS_with_abstract_class.phpt b/ext/pdo/tests/attr_statement_class/pdo_ATTR_STATEMENT_CLASS_with_abstract_class.phpt index 339f4ec0be58..049d094462ed 100644 --- a/ext/pdo/tests/attr_statement_class/pdo_ATTR_STATEMENT_CLASS_with_abstract_class.phpt +++ b/ext/pdo/tests/attr_statement_class/pdo_ATTR_STATEMENT_CLASS_with_abstract_class.phpt @@ -38,5 +38,4 @@ $db = PDOTest::factory(); PDOTest::dropTableIfExists($db, "pdo_attr_statement_class_abstract"); ?> --EXPECT-- -bool(true) Error: Cannot instantiate abstract class DerivedButAbstract diff --git a/ext/pdo/tests/pdo_036.phpt b/ext/pdo/tests/pdo_036.phpt index 10fe22193017..9e745a3ac622 100644 --- a/ext/pdo/tests/pdo_036.phpt +++ b/ext/pdo/tests/pdo_036.phpt @@ -36,7 +36,7 @@ object(PDOStatement)#2 (1) { } Property queryString is read only -Fatal error: Uncaught PDOException: You may not create a PDORow manually in %spdo_036.php:%d +Fatal error: Uncaught ReflectionException: A PDORow class cannot be manually instantiated in %s:%d Stack trace: #0 %spdo_036.php(%d): ReflectionClass->newInstance() #1 {main} diff --git a/ext/pdo/tests/pdo_fetch_class_opaque_object.phpt b/ext/pdo/tests/pdo_fetch_class_opaque_object.phpt index eaef3f6e8f35..34fe6d1f5149 100644 --- a/ext/pdo/tests/pdo_fetch_class_opaque_object.phpt +++ b/ext/pdo/tests/pdo_fetch_class_opaque_object.phpt @@ -23,7 +23,11 @@ $db->exec("INSERT INTO pdo_fetch_class_opaque_object VALUES(3, 'CC')"); $stmt = $db->prepare('SELECT path FROM pdo_fetch_class_opaque_object'); $stmt->execute(); -var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'Directory', [])); +try { + var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'Directory', [])); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} ?> --CLEAN-- ---EXPECTF-- -array(3) { - [0]=> - object(Directory)#%s (1) { - ["path"]=> - string(2) "AA" - ["handle"]=> - uninitialized(mixed) - } - [1]=> - object(Directory)#%s (1) { - ["path"]=> - string(2) "BB" - ["handle"]=> - uninitialized(mixed) - } - [2]=> - object(Directory)#%s (1) { - ["path"]=> - string(2) "CC" - ["handle"]=> - uninitialized(mixed) - } -} +--EXPECT-- +Error: Cannot instantiate an object of class Directory diff --git a/ext/pdo/tests/pdorow.phpt b/ext/pdo/tests/pdorow.phpt index 92870e97a744..3752361163cd 100644 --- a/ext/pdo/tests/pdorow.phpt +++ b/ext/pdo/tests/pdorow.phpt @@ -9,7 +9,7 @@ new PDORow; ?> --EXPECTF-- -Fatal error: Uncaught PDOException: You may not create a PDORow manually in %spdorow.php:3 +Fatal error: Uncaught Error: A PDORow class cannot be manually instantiated in %s:%d Stack trace: #0 {main} thrown in %spdorow.php on line 3 diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c index 8efd43ed3a8b..1d6dbca0b5b2 100644 --- a/ext/pgsql/pgsql.c +++ b/ext/pgsql/pgsql.c @@ -166,11 +166,6 @@ static zend_object *pgsql_link_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *pgsql_link_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct PgSql\\Connection, use pg_connect() or pg_pconnect() instead"); - return NULL; -} - static void pgsql_link_free(pgsql_link_handle *link) { PGresult *res; @@ -222,11 +217,6 @@ static zend_object *pgsql_result_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *pgsql_result_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct PgSql\\Result, use a dedicated function instead"); - return NULL; -} - static void pgsql_result_free(pgsql_result_handle *pg_result) { PQclear(pg_result->result); @@ -259,11 +249,6 @@ static zend_object *pgsql_lob_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *pgsql_lob_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct PgSql\\Lob, use pg_lo_open() instead"); - return NULL; -} - static void pgsql_lob_free_obj(zend_object *obj) { pgLofp *lofp = pgsql_lob_from_obj(obj); @@ -576,7 +561,6 @@ PHP_MINIT_FUNCTION(pgsql) memcpy(&pgsql_link_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); pgsql_link_object_handlers.offset = offsetof(pgsql_link_handle, std); pgsql_link_object_handlers.free_obj = pgsql_link_free_obj; - pgsql_link_object_handlers.get_constructor = pgsql_link_get_constructor; pgsql_link_object_handlers.clone_obj = NULL; pgsql_link_object_handlers.compare = zend_objects_not_comparable; @@ -587,7 +571,6 @@ PHP_MINIT_FUNCTION(pgsql) memcpy(&pgsql_result_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); pgsql_result_object_handlers.offset = offsetof(pgsql_result_handle, std); pgsql_result_object_handlers.free_obj = pgsql_result_free_obj; - pgsql_result_object_handlers.get_constructor = pgsql_result_get_constructor; pgsql_result_object_handlers.clone_obj = NULL; pgsql_result_object_handlers.compare = zend_objects_not_comparable; @@ -598,7 +581,6 @@ PHP_MINIT_FUNCTION(pgsql) memcpy(&pgsql_lob_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); pgsql_lob_object_handlers.offset = offsetof(pgLofp, std); pgsql_lob_object_handlers.free_obj = pgsql_lob_free_obj; - pgsql_lob_object_handlers.get_constructor = pgsql_lob_get_constructor; pgsql_lob_object_handlers.clone_obj = NULL; pgsql_lob_object_handlers.compare = zend_objects_not_comparable; @@ -2129,6 +2111,19 @@ PHP_FUNCTION(pg_fetch_object) ce = zend_standard_class_def; } + if (UNEXPECTED(!zend_is_class_instantiable(ce))) { + zend_argument_value_error(3, "Class \"%s\" cannot be instantiated", ZSTR_VAL(ce->name)); + RETURN_THROWS(); + } + + if (UNEXPECTED(!ce->constructor && ctor_params && zend_hash_num_elements(ctor_params) > 0)) { + zend_argument_value_error(4, + "must be empty when the specified class (%s) does not have a constructor", + ZSTR_VAL(ce->name) + ); + RETURN_THROWS(); + } + if (UNEXPECTED(object_init_ex(return_value, ce) == FAILURE)) { RETURN_THROWS(); } @@ -2148,26 +2143,8 @@ PHP_FUNCTION(pg_fetch_object) } zend_object *obj = Z_OBJ_P(return_value); - const zend_class_entry *old = EG(fake_scope); - EG(fake_scope) = ce; - zend_function *constructor = obj->handlers->get_constructor(obj); - EG(fake_scope) = old; - - if (UNEXPECTED(EG(exception))) { - /* visibility error or override refused - VM dtors return_value */ - return; - } - - if (UNEXPECTED(!constructor && ctor_params && zend_hash_num_elements(ctor_params) > 0)) { - zend_argument_value_error(4, - "must be empty when the specified class (%s) does not have a constructor", - ZSTR_VAL(ce->name) - ); - RETURN_THROWS(); - } - - if (constructor) { - zend_call_known_function(constructor, obj, ce, + if (ce->constructor) { + zend_call_known_function(ce->constructor, obj, ce, /* retval */ NULL, /* argc */ 0, /* params */ NULL, ctor_params); if (EG(exception)) { zend_object_store_ctor_failed(obj); diff --git a/ext/pgsql/pgsql.stub.php b/ext/pgsql/pgsql.stub.php index 52ddc3b3748a..df5b047f6258 100644 --- a/ext/pgsql/pgsql.stub.php +++ b/ext/pgsql/pgsql.stub.php @@ -965,6 +965,7 @@ function pg_close_stmt(Pgsql\Connection $connection, string $statement_name): Pg * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct PgSql\\Connection, use pg_connect() or pg_pconnect() instead")] final class Connection { } @@ -973,6 +974,7 @@ final class Connection * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct PgSql\\Result, use a dedicated function instead")] final class Result { } @@ -981,6 +983,7 @@ final class Result * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct PgSql\\Connection, use pg_lo_open() instead")] final class Lob { } diff --git a/ext/pgsql/pgsql_arginfo.h b/ext/pgsql/pgsql_arginfo.h index 63a1d185d535..4d5451d62b20 100644 --- a/ext/pgsql/pgsql_arginfo.h +++ b/ext/pgsql/pgsql_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit pgsql.stub.php instead. - * Stub hash: f25b5a574c96d4bc2f08b8cacab16f499a164a6b */ + * Stub hash: 93b2a5552d8409f2f31be6162b7be0836e771b28 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_connect, 0, 1, PgSql\\Connection, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0) @@ -1031,6 +1031,14 @@ static zend_class_entry *register_class_PgSql_Connection(void) INIT_NS_CLASS_ENTRY(ce, "PgSql", "Connection", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_PgSql_Connection_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_PgSql_Connection_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_PgSql_Connection_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_PgSql_Connection_0, true); + zend_string *attribute_NonInstantiableClass_class_PgSql_Connection_0_arg0_str = zend_string_init("Cannot directly construct PgSql\\Connection, use pg_connect() or pg_pconnect() instead", strlen("Cannot directly construct PgSql\\Connection, use pg_connect() or pg_pconnect() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_PgSql_Connection_0->args[0].value, attribute_NonInstantiableClass_class_PgSql_Connection_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -1041,6 +1049,14 @@ static zend_class_entry *register_class_PgSql_Result(void) INIT_NS_CLASS_ENTRY(ce, "PgSql", "Result", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_PgSql_Result_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_PgSql_Result_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_PgSql_Result_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_PgSql_Result_0, true); + zend_string *attribute_NonInstantiableClass_class_PgSql_Result_0_arg0_str = zend_string_init("Cannot directly construct PgSql\\Result, use a dedicated function instead", strlen("Cannot directly construct PgSql\\Result, use a dedicated function instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_PgSql_Result_0->args[0].value, attribute_NonInstantiableClass_class_PgSql_Result_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -1051,5 +1067,13 @@ static zend_class_entry *register_class_PgSql_Lob(void) INIT_NS_CLASS_ENTRY(ce, "PgSql", "Lob", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_PgSql_Lob_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_PgSql_Lob_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_PgSql_Lob_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_PgSql_Lob_0, true); + zend_string *attribute_NonInstantiableClass_class_PgSql_Lob_0_arg0_str = zend_string_init("Cannot directly construct PgSql\\Connection, use pg_lo_open() instead", strlen("Cannot directly construct PgSql\\Connection, use pg_lo_open() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_PgSql_Lob_0->args[0].value, attribute_NonInstantiableClass_class_PgSql_Lob_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/pgsql/tests/pg_fetch_object_with_abstract_class.phpt b/ext/pgsql/tests/pg_fetch_object_with_abstract_class.phpt index b3e6ea7f7b36..6dfb668834bc 100644 --- a/ext/pgsql/tests/pg_fetch_object_with_abstract_class.phpt +++ b/ext/pgsql/tests/pg_fetch_object_with_abstract_class.phpt @@ -54,6 +54,6 @@ $db = @pg_connect($conn_str); @pg_query($db, "DROP TABLE IF EXISTS pg_fetch_object_abstract_class cascade"); ?> --EXPECT-- -Error: Cannot instantiate interface I -Error: Cannot instantiate abstract class C -Error: Cannot instantiate enum E +ValueError: pg_fetch_object(): Argument #3 ($class) Class "I" cannot be instantiated +ValueError: pg_fetch_object(): Argument #3 ($class) Class "C" cannot be instantiated +ValueError: pg_fetch_object(): Argument #3 ($class) Class "E" cannot be instantiated diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 50bcf4cb79c1..3bb59f9c81bb 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -4451,7 +4451,7 @@ ZEND_METHOD(ReflectionClass, getConstructor) ZEND_PARSE_PARAMETERS_NONE(); GET_REFLECTION_OBJECT_PTR(ce); - if (ce->constructor) { + if (ce->constructor && !zend_is_non_instantiable_constructor(ce->constructor)) { reflection_method_factory(ce, ce->constructor, NULL, return_value); } else { RETURN_NULL(); @@ -4901,17 +4901,8 @@ ZEND_METHOD(ReflectionClass, isInstantiable) ZEND_PARSE_PARAMETERS_NONE(); 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)) { - RETURN_FALSE; - } - - /* Basically, the class is instantiable. Though, if there is a constructor - * and it is not publicly accessible, it isn't! */ - if (!ce->constructor) { - RETURN_TRUE; - } - RETURN_BOOL(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC); + RETURN_BOOL(zend_is_class_instantiable(ce)); } /* }}} */ @@ -4997,6 +4988,15 @@ ZEND_METHOD(ReflectionClass, getModifiers) } /* }}} */ +static ZEND_COLD void reflection_not_instantiable_class(const zend_class_entry* ce) { + if (ce->ce_flags & ZEND_ACC_UNINSTANTIABLE + || (ce->constructor && zend_is_non_instantiable_constructor(ce->constructor))) { + zend_cannot_instantiate_class_ex(ce, NULL, reflection_exception_ptr); + } else { + zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name)); + } +} + /* {{{ Returns whether the given object is an instance of this class */ ZEND_METHOD(ReflectionClass, isInstance) { @@ -5017,44 +5017,36 @@ ZEND_METHOD(ReflectionClass, newInstance) { reflection_object *intern; zend_class_entry *ce; - zend_function *constructor; GET_REFLECTION_OBJECT_PTR(ce); - if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) { - return; + if (UNEXPECTED(!zend_is_class_instantiable(ce))) { + reflection_not_instantiable_class(ce); + RETURN_THROWS(); } - const zend_class_entry *old_scope = EG(fake_scope); - EG(fake_scope) = ce; - constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value)); - EG(fake_scope) = old_scope; + if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) { + RETURN_THROWS(); + } - /* Run the constructor if there is one */ - if (constructor) { - zval *params; - int num_args; - HashTable *named_params; - - if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name)); - zval_ptr_dtor(return_value); - RETURN_NULL(); - } + /* Run the constructor */ + zval *params; + uint32_t num_args; + HashTable *named_params; - ZEND_PARSE_PARAMETERS_START(0, -1) - Z_PARAM_VARIADIC_WITH_NAMED(params, num_args, named_params) - ZEND_PARSE_PARAMETERS_END(); + ZEND_PARSE_PARAMETERS_START(0, -1) + Z_PARAM_VARIADIC_WITH_NAMED(params, num_args, named_params) + ZEND_PARSE_PARAMETERS_END(); + /* Run the constructor if there is one */ + if (ce->constructor) { zend_call_known_function( - constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, + ce->constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, num_args, params, named_params); if (EG(exception)) { zend_object_store_ctor_failed(Z_OBJ_P(return_value)); } - } else if (ZEND_NUM_ARGS()) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ZSTR_VAL(ce->name)); } } /* }}} */ @@ -5069,6 +5061,11 @@ ZEND_METHOD(ReflectionClass, newInstanceWithoutConstructor) ZEND_PARSE_PARAMETERS_NONE(); + if (UNEXPECTED(!zend_is_class_instantiable_ignoring_ctor_visibility(ce))) { + zend_cannot_instantiate_class_ex(ce, NULL, reflection_exception_ptr); + RETURN_THROWS(); + } + if (ce->type == ZEND_INTERNAL_CLASS && ce->create_object != NULL && (ce->ce_flags & ZEND_ACC_FINAL)) { zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s is an internal class marked as final that cannot be instantiated without invoking its constructor", ZSTR_VAL(ce->name)); @@ -5084,9 +5081,7 @@ ZEND_METHOD(ReflectionClass, newInstanceArgs) { reflection_object *intern; zend_class_entry *ce; - int argc = 0; HashTable *args = NULL; - zend_function *constructor; GET_REFLECTION_OBJECT_PTR(ce); @@ -5094,35 +5089,23 @@ ZEND_METHOD(ReflectionClass, newInstanceArgs) RETURN_THROWS(); } - if (args) { - argc = zend_hash_num_elements(args); + if (UNEXPECTED(!zend_is_class_instantiable(ce))) { + reflection_not_instantiable_class(ce); + RETURN_THROWS(); } if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) { - return; + RETURN_THROWS(); } - const zend_class_entry *old_scope = EG(fake_scope); - EG(fake_scope) = ce; - constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value)); - EG(fake_scope) = old_scope; - /* Run the constructor if there is one */ - if (constructor) { - if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name)); - zval_ptr_dtor(return_value); - RETURN_NULL(); - } - + if (ce->constructor) { zend_call_known_function( - constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, 0, NULL, args); + ce->constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, 0, NULL, args); if (EG(exception)) { zend_object_store_ctor_failed(Z_OBJ_P(return_value)); } - } else if (argc) { - zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ZSTR_VAL(ce->name)); } } /* }}} */ diff --git a/ext/reflection/tests/007.phpt b/ext/reflection/tests/007.phpt index 8e90f7a010a9..172d46539195 100644 --- a/ext/reflection/tests/007.phpt +++ b/ext/reflection/tests/007.phpt @@ -97,9 +97,11 @@ string(43) "Class "Class_does_not_exist" does not exist" object(NoCtor)#%d (0) { } ====>newInstance(25) -string(86) "Class NoCtor does not have a constructor, so you cannot pass any constructor arguments" +object(NoCtor)#%d (0) { +} ====>newInstance(25, 42) -string(86) "Class NoCtor does not have a constructor, so you cannot pass any constructor arguments" +object(NoCtor)#%d (0) { +} ====>WithCtor ====>newInstance() diff --git a/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt b/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt index 7dded54d3fae..622d9a35b446 100644 --- a/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt +++ b/ext/reflection/tests/ReflectionClass_newInstanceArgs_001.phpt @@ -59,7 +59,7 @@ var_dump($e1); try { $e2 = $rcE->newInstanceArgs(array('x')); - echo "you should not see this\n"; + echo "No explicit construct still allows instantiation\n"; } catch (Exception $e) { echo $e->getMessage() . "\n"; } @@ -73,4 +73,4 @@ Access to non-public constructor of class C Access to non-public constructor of class D object(E)#%d (0) { } -Class E does not have a constructor, so you cannot pass any constructor arguments +No explicit construct still allows instantiation diff --git a/ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt b/ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt index 59337f09e8b4..835c91a1ab7f 100644 --- a/ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt +++ b/ext/reflection/tests/ReflectionClass_newInstanceWithoutConstructor.phpt @@ -42,7 +42,7 @@ object(stdClass)#%d (0) { } object(DateTime)#%d (0) { } -Class Generator is an internal class marked as final that cannot be instantiated without invoking its constructor +The "Generator" class is reserved for internal use and cannot be manually instantiated object(Bar)#%d (1) { ["storage":"ArrayObject":private]=> array(0) { diff --git a/ext/reflection/tests/ReflectionClass_newInstance_001.phpt b/ext/reflection/tests/ReflectionClass_newInstance_001.phpt index 22d06e328270..c67aceb3137d 100644 --- a/ext/reflection/tests/ReflectionClass_newInstance_001.phpt +++ b/ext/reflection/tests/ReflectionClass_newInstance_001.phpt @@ -62,7 +62,7 @@ var_dump($e1); try { $e2 = $rcE->newInstance('x'); - echo "you should not see this\n"; + echo "Can pass extra args to implicit constructor\n"; } catch (Exception $e) { echo $e->getMessage() . "\n"; } @@ -76,4 +76,4 @@ Access to non-public constructor of class C Access to non-public constructor of class D object(E)#%d (0) { } -Class E does not have a constructor, so you cannot pass any constructor arguments +Can pass extra args to implicit constructor diff --git a/ext/reflection/tests/bug52854.phpt b/ext/reflection/tests/bug52854.phpt index 2d174bc11eba..962a699e1124 100644 --- a/ext/reflection/tests/bug52854.phpt +++ b/ext/reflection/tests/bug52854.phpt @@ -25,4 +25,5 @@ object(Test)#%d (0) { } object(Test)#%d (0) { } -Class Test does not have a constructor, so you cannot pass any constructor arguments +object(Test)#%d (0) { +} diff --git a/ext/reflection/tests/bug64007.phpt b/ext/reflection/tests/bug64007.phpt index a25beb6360d7..81855d914441 100644 --- a/ext/reflection/tests/bug64007.phpt +++ b/ext/reflection/tests/bug64007.phpt @@ -6,18 +6,17 @@ $reflection = new ReflectionClass('Generator'); try { $generator = $reflection->newInstanceWithoutConstructor(); var_dump($generator); -} catch (Exception $e) { - var_dump($e->getMessage()); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; } -$generator = $reflection->newInstance(); -var_dump($generator); +try { + $generator = $reflection->newInstance(); + var_dump($generator); +} catch (Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} ?> ---EXPECTF-- -string(%d) "Class Generator is an internal class marked as final that cannot be instantiated without invoking its constructor" - -Fatal error: Uncaught Error: The "Generator" class is reserved for internal use and cannot be manually instantiated in %sbug64007.php:%d -Stack trace: -#0 %s(%d): ReflectionClass->newInstance() -#1 {main} - thrown in %sbug64007.php on line %d +--EXPECT-- +ReflectionException: The "Generator" class is reserved for internal use and cannot be manually instantiated +ReflectionException: The "Generator" class is reserved for internal use and cannot be manually instantiated diff --git a/ext/shmop/shmop.c b/ext/shmop/shmop.c index 8721e4333ce8..99b23e1b05da 100644 --- a/ext/shmop/shmop.c +++ b/ext/shmop/shmop.c @@ -85,12 +85,6 @@ static zend_object *shmop_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *shmop_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct Shmop, use shmop_open() instead"); - return NULL; -} - static void shmop_free_obj(zend_object *object) { php_shmop *shmop = shmop_from_obj(object); @@ -110,7 +104,6 @@ PHP_MINIT_FUNCTION(shmop) memcpy(&shmop_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); shmop_object_handlers.offset = offsetof(php_shmop, std); shmop_object_handlers.free_obj = shmop_free_obj; - shmop_object_handlers.get_constructor = shmop_get_constructor; shmop_object_handlers.clone_obj = NULL; shmop_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/shmop/shmop.stub.php b/ext/shmop/shmop.stub.php index 1694105745a8..96cb76ef5c37 100644 --- a/ext/shmop/shmop.stub.php +++ b/ext/shmop/shmop.stub.php @@ -6,6 +6,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct Shmop, use shmop_open() instead")] final class Shmop {} function shmop_open(int $key, string $mode, int $permissions, int $size): Shmop|false {} diff --git a/ext/shmop/shmop_arginfo.h b/ext/shmop/shmop_arginfo.h index 9d88fe63c32b..7b5fdd1500ad 100644 --- a/ext/shmop/shmop_arginfo.h +++ b/ext/shmop/shmop_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit shmop.stub.php instead. - * Stub hash: e7f250077b6721539caee96afe4ed392396018f9 */ + * Stub hash: 0a6a1bf8f5803c3b41ccffe587b5111515b83bf5 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_shmop_open, 0, 4, Shmop, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_LONG, 0) @@ -67,5 +67,13 @@ static zend_class_entry *register_class_Shmop(void) INIT_CLASS_ENTRY(ce, "Shmop", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Shmop_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Shmop_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Shmop_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Shmop_0, true); + zend_string *attribute_NonInstantiableClass_class_Shmop_0_arg0_str = zend_string_init("Cannot directly construct Shmop, use shmop_open() instead", strlen("Cannot directly construct Shmop, use shmop_open() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Shmop_0->args[0].value, attribute_NonInstantiableClass_class_Shmop_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/soap/soap.c b/ext/soap/soap.c index da5e10ac3258..1fb3ac0ddb43 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -268,13 +268,6 @@ static void soap_url_object_free(zend_object *obj) zend_object_std_dtor(&url_obj->std); } -static zend_function *soap_url_object_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct Soap\\Url"); - - return NULL; -} - static zend_result soap_url_cast_object(zend_object *obj, zval *result, int type) { if (type == IS_LONG) { @@ -315,13 +308,6 @@ static void soap_sdl_object_free(zend_object *obj) zend_object_std_dtor(&sdl_obj->std); } -static zend_function *soap_sdl_object_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct Soap\\Sdl"); - - return NULL; -} - static zend_result soap_sdl_cast_object(zend_object *obj, zval *result, int type) { if (type == IS_LONG) { @@ -564,7 +550,6 @@ PHP_MINIT_FUNCTION(soap) memcpy(&soap_url_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); soap_url_object_handlers.offset = offsetof(soap_url_object, std); soap_url_object_handlers.free_obj = soap_url_object_free; - soap_url_object_handlers.get_constructor = soap_url_object_get_constructor; soap_url_object_handlers.clone_obj = NULL; soap_url_object_handlers.cast_object = soap_url_cast_object; soap_url_object_handlers.compare = zend_objects_not_comparable; @@ -576,7 +561,6 @@ PHP_MINIT_FUNCTION(soap) memcpy(&soap_sdl_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); soap_sdl_object_handlers.offset = offsetof(soap_sdl_object, std); soap_sdl_object_handlers.free_obj = soap_sdl_object_free; - soap_sdl_object_handlers.get_constructor = soap_sdl_object_get_constructor; soap_sdl_object_handlers.clone_obj = NULL; soap_url_object_handlers.cast_object = soap_sdl_cast_object; soap_sdl_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/soap/soap.stub.php b/ext/soap/soap.stub.php index fdd4a46e109f..ad5ebf936c6f 100644 --- a/ext/soap/soap.stub.php +++ b/ext/soap/soap.stub.php @@ -7,6 +7,7 @@ * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct Soap\\Url")] final class Url { } @@ -15,6 +16,7 @@ final class Url * @strict-properties * @not-serializable */ + #[\NonInstantiableClass("Cannot directly construct Soap\\Sdl")] final class Sdl { } diff --git a/ext/soap/soap_arginfo.h b/ext/soap/soap_arginfo.h index 2f7d56ca4221..cea90882509d 100644 --- a/ext/soap/soap_arginfo.h +++ b/ext/soap/soap_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit soap.stub.php instead. - * Stub hash: 14c74a5d6f547837f536920d5abb741e2b6e4373 */ + * Stub hash: 8f2911fbdbcce57883cf744bb0f0be4879389418 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_use_soap_error_handler, 0, 0, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, enable, _IS_BOOL, 0, "true") @@ -333,6 +333,14 @@ static zend_class_entry *register_class_Soap_Url(void) INIT_NS_CLASS_ENTRY(ce, "Soap", "Url", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Soap_Url_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Soap_Url_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Soap_Url_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Soap_Url_0, true); + zend_string *attribute_NonInstantiableClass_class_Soap_Url_0_arg0_str = zend_string_init("Cannot directly construct Soap\\Url", strlen("Cannot directly construct Soap\\Url"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Soap_Url_0->args[0].value, attribute_NonInstantiableClass_class_Soap_Url_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -343,6 +351,14 @@ static zend_class_entry *register_class_Soap_Sdl(void) INIT_NS_CLASS_ENTRY(ce, "Soap", "Sdl", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Soap_Sdl_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Soap_Sdl_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Soap_Sdl_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Soap_Sdl_0, true); + zend_string *attribute_NonInstantiableClass_class_Soap_Sdl_0_arg0_str = zend_string_init("Cannot directly construct Soap\\Sdl", strlen("Cannot directly construct Soap\\Sdl"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Soap_Sdl_0->args[0].value, attribute_NonInstantiableClass_class_Soap_Sdl_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 7b87a2a2f9bd..d2cb66fa6edc 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -27,6 +27,7 @@ #include "ext/standard/file.h" #include "ext/standard/info.h" #include "php_ini.h" +#include "zend_attributes.h" #ifdef PHP_WIN32 # include "windows_common.h" # include @@ -140,11 +141,6 @@ static zend_object *socket_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *socket_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct Socket, use socket_create() instead"); - return NULL; -} - static void socket_free_obj(zend_object *object) { php_socket *socket = socket_from_obj(object); @@ -195,11 +191,6 @@ static zend_object *address_info_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *address_info_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct AddressInfo, use socket_addrinfo_lookup() instead"); - return NULL; -} - static void address_info_free_obj(zend_object *object) { php_addrinfo *address_info = address_info_from_obj(object); @@ -486,7 +477,6 @@ static PHP_MINIT_FUNCTION(sockets) memcpy(&socket_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); socket_object_handlers.offset = offsetof(php_socket, std); socket_object_handlers.free_obj = socket_free_obj; - socket_object_handlers.get_constructor = socket_get_constructor; socket_object_handlers.clone_obj = NULL; socket_object_handlers.get_gc = socket_get_gc; socket_object_handlers.compare = zend_objects_not_comparable; @@ -498,7 +488,6 @@ static PHP_MINIT_FUNCTION(sockets) memcpy(&address_info_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); address_info_object_handlers.offset = offsetof(php_addrinfo, std); address_info_object_handlers.free_obj = address_info_free_obj; - address_info_object_handlers.get_constructor = address_info_get_constructor; address_info_object_handlers.clone_obj = NULL; address_info_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/sockets/sockets.stub.php b/ext/sockets/sockets.stub.php index 56b2ac07e868..511b4226fe81 100644 --- a/ext/sockets/sockets.stub.php +++ b/ext/sockets/sockets.stub.php @@ -2201,6 +2201,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct Socket, use socket_create() instead")] final class Socket { } @@ -2209,6 +2210,7 @@ final class Socket * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct AddressInfo, use socket_addrinfo_lookup() instead")] final class AddressInfo { } diff --git a/ext/sockets/sockets_arginfo.h b/ext/sockets/sockets_arginfo.h index 2592cb740865..15dade755364 100644 --- a/ext/sockets/sockets_arginfo.h +++ b/ext/sockets/sockets_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit sockets.stub.php instead. - * Stub hash: 5e71ef16f2121bd6c75794673d0e0a394759ff8b */ + * Stub hash: 38a80f6141e44f7d517df52f5e8e82e0accd3e33 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_socket_select, 0, 4, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(1, read, IS_ARRAY, 1) @@ -1118,6 +1118,14 @@ static zend_class_entry *register_class_Socket(void) INIT_CLASS_ENTRY(ce, "Socket", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_Socket_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Socket_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Socket_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Socket_0, true); + zend_string *attribute_NonInstantiableClass_class_Socket_0_arg0_str = zend_string_init("Cannot directly construct Socket, use socket_create() instead", strlen("Cannot directly construct Socket, use socket_create() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Socket_0->args[0].value, attribute_NonInstantiableClass_class_Socket_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -1128,5 +1136,13 @@ static zend_class_entry *register_class_AddressInfo(void) INIT_CLASS_ENTRY(ce, "AddressInfo", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_AddressInfo_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_AddressInfo_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_AddressInfo_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_AddressInfo_0, true); + zend_string *attribute_NonInstantiableClass_class_AddressInfo_0_arg0_str = zend_string_init("Cannot directly construct AddressInfo, use socket_addrinfo_lookup() instead", strlen("Cannot directly construct AddressInfo, use socket_addrinfo_lookup() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_AddressInfo_0->args[0].value, attribute_NonInstantiableClass_class_AddressInfo_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 2a0e7a786738..bcf6fdfbb4f4 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -289,6 +289,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */ register_basic_functions_symbols(module_number); + /* TODO: Should manual instantiation be allowed? */ php_ce_incomplete_class = register_class___PHP_Incomplete_Class(); php_register_incomplete_class_handlers(); diff --git a/ext/standard/dir.c b/ext/standard/dir.c index f313d5f539d1..f6f6f16caded 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -14,6 +14,7 @@ /* {{{ includes/startup/misc */ +#include "zend_attributes.h" #include "php.h" #include "fopen_wrappers.h" #include "file.h" @@ -51,12 +52,6 @@ static zend_object_handlers dir_class_object_handlers; #define Z_DIRECTORY_PATH_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 0) #define Z_DIRECTORY_HANDLE_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 1) -static zend_function *dir_class_get_constructor(zend_object *object) -{ - zend_throw_error(NULL, "Cannot directly construct Directory, use dir() instead"); - return NULL; -} - static void php_set_default_dir(zend_resource *res) { if (DIRG(default_dir)) { @@ -90,7 +85,6 @@ PHP_MINIT_FUNCTION(dir) dir_class_entry_ptr->default_object_handlers = &dir_class_object_handlers; memcpy(&dir_class_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); - dir_class_object_handlers.get_constructor = dir_class_get_constructor; dir_class_object_handlers.clone_obj = NULL; dir_class_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/standard/dir.stub.php b/ext/standard/dir.stub.php index 6b5ef51c13bb..c964dff4a02d 100644 --- a/ext/standard/dir.stub.php +++ b/ext/standard/dir.stub.php @@ -89,6 +89,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct Directory, use dir() instead")] final class Directory { public readonly string $path; diff --git a/ext/standard/dir_arginfo.h b/ext/standard/dir_arginfo.h index 7ff39528d526..2c80e17320b7 100644 --- a/ext/standard/dir_arginfo.h +++ b/ext/standard/dir_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit dir.stub.php instead. - * Stub hash: e21d382cd4001001874c49d8c5244efb57613910 */ + * Stub hash: 51ee840fe6f7af828d6f031730136b046f8ffc55 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Directory_close, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -70,5 +70,13 @@ static zend_class_entry *register_class_Directory(void) zend_declare_typed_property(class_entry, property_handle_name, &property_handle_default_value, ZEND_ACC_PUBLIC|ZEND_ACC_READONLY, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_ANY)); zend_string_release_ex(property_handle_name, true); + zend_string *attribute_name_NonInstantiableClass_class_Directory_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_Directory_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_Directory_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_Directory_0, true); + zend_string *attribute_NonInstantiableClass_class_Directory_0_arg0_str = zend_string_init("Cannot directly construct Directory, use dir() instead", strlen("Cannot directly construct Directory, use dir() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_Directory_0->args[0].value, attribute_NonInstantiableClass_class_Directory_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt b/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt index 95999581f31c..8a912bd00d22 100644 --- a/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt +++ b/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt @@ -11,20 +11,7 @@ try { echo $e::class, ': ', $e->getMessage(), PHP_EOL; } -var_dump($d); -try { - var_dump($d->read()); -} catch (\Throwable $e) { - echo $e::class, ': ', $e->getMessage(), PHP_EOL; -} - ?> --EXPECT-- -bool(true) -object(Directory)#2 (0) { - ["path"]=> - uninitialized(string) - ["handle"]=> - uninitialized(mixed) -} -Error: Internal directory stream has been altered +bool(false) +ReflectionException: Cannot directly construct Directory, use dir() instead diff --git a/ext/sysvmsg/sysvmsg.c b/ext/sysvmsg/sysvmsg.c index 16b4ffec50ee..814d73d92060 100644 --- a/ext/sysvmsg/sysvmsg.c +++ b/ext/sysvmsg/sysvmsg.c @@ -19,9 +19,10 @@ #include "php.h" #include "ext/standard/info.h" #include "php_sysvmsg.h" -#include "sysvmsg_arginfo.h" #include "ext/standard/php_var.h" #include "zend_smart_str.h" +#include "zend_attributes.h" +#include "sysvmsg_arginfo.h" #include #include @@ -80,11 +81,6 @@ static zend_object *sysvmsg_queue_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *sysvmsg_queue_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct SysvMessageQueue, use msg_get_queue() instead"); - return NULL; -} - static void sysvmsg_queue_free_obj(zend_object *object) { sysvmsg_queue_t *sysvmsg_queue = sysvmsg_queue_from_obj(object); @@ -103,7 +99,6 @@ PHP_MINIT_FUNCTION(sysvmsg) memcpy(&sysvmsg_queue_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); sysvmsg_queue_object_handlers.offset = offsetof(sysvmsg_queue_t, std); sysvmsg_queue_object_handlers.free_obj = sysvmsg_queue_free_obj; - sysvmsg_queue_object_handlers.get_constructor = sysvmsg_queue_get_constructor; sysvmsg_queue_object_handlers.clone_obj = NULL; sysvmsg_queue_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/sysvmsg/sysvmsg.stub.php b/ext/sysvmsg/sysvmsg.stub.php index 6f94167ac7b9..edaac05d3cce 100644 --- a/ext/sysvmsg/sysvmsg.stub.php +++ b/ext/sysvmsg/sysvmsg.stub.php @@ -32,6 +32,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct SysvMessageQueue, use msg_get_queue() instead")] final class SysvMessageQueue { } diff --git a/ext/sysvmsg/sysvmsg_arginfo.h b/ext/sysvmsg/sysvmsg_arginfo.h index 9dee3e0f4840..e9c731317335 100644 --- a/ext/sysvmsg/sysvmsg_arginfo.h +++ b/ext/sysvmsg/sysvmsg_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit sysvmsg.stub.php instead. - * Stub hash: ed5b1e4e5dda6a65ce336fc4daa975520c354f17 */ + * Stub hash: 43f34e025ca7978faedc724af45952fe3fd16d4f */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_msg_get_queue, 0, 1, SysvMessageQueue, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_LONG, 0) @@ -78,5 +78,13 @@ static zend_class_entry *register_class_SysvMessageQueue(void) INIT_CLASS_ENTRY(ce, "SysvMessageQueue", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_SysvMessageQueue_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_SysvMessageQueue_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_SysvMessageQueue_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_SysvMessageQueue_0, true); + zend_string *attribute_NonInstantiableClass_class_SysvMessageQueue_0_arg0_str = zend_string_init("Cannot directly construct SysvMessageQueue, use msg_get_queue() instead", strlen("Cannot directly construct SysvMessageQueue, use msg_get_queue() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_SysvMessageQueue_0->args[0].value, attribute_NonInstantiableClass_class_SysvMessageQueue_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/sysvsem/sysvsem.c b/ext/sysvsem/sysvsem.c index 9d3990d0bdc0..968daeb96334 100644 --- a/ext/sysvsem/sysvsem.c +++ b/ext/sysvsem/sysvsem.c @@ -26,9 +26,10 @@ #include #include -#include "sysvsem_arginfo.h" #include "php_sysvsem.h" #include "ext/standard/info.h" +#include "zend_attributes.h" +#include "sysvsem_arginfo.h" #ifndef HAVE_UNION_SEMUN union semun { @@ -97,11 +98,6 @@ static zend_object *sysvsem_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *sysvsem_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct SysvSemaphore, use sem_get() instead"); - return NULL; -} - static void sysvsem_free_obj(zend_object *object) { sysvsem_sem *sem_ptr = sysvsem_from_obj(object); @@ -149,7 +145,6 @@ PHP_MINIT_FUNCTION(sysvsem) memcpy(&sysvsem_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); sysvsem_object_handlers.offset = offsetof(sysvsem_sem, std); sysvsem_object_handlers.free_obj = sysvsem_free_obj; - sysvsem_object_handlers.get_constructor = sysvsem_get_constructor; sysvsem_object_handlers.clone_obj = NULL; sysvsem_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/sysvsem/sysvsem.stub.php b/ext/sysvsem/sysvsem.stub.php index d8e10a5f917e..4077e547a5d9 100644 --- a/ext/sysvsem/sysvsem.stub.php +++ b/ext/sysvsem/sysvsem.stub.php @@ -6,6 +6,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct SysvSemaphore, use sem_get() instead")] final class SysvSemaphore { } diff --git a/ext/sysvsem/sysvsem_arginfo.h b/ext/sysvsem/sysvsem_arginfo.h index b7643a926b14..ef630d3e8b75 100644 --- a/ext/sysvsem/sysvsem_arginfo.h +++ b/ext/sysvsem/sysvsem_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit sysvsem.stub.php instead. - * Stub hash: 946ea9d0d2156ced1bac460d7d5fc3420e1934bb */ + * Stub hash: 68b3058bcd5654ca98163bc42081cd31e792ff8d */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_sem_get, 0, 1, SysvSemaphore, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_LONG, 0) @@ -39,5 +39,13 @@ static zend_class_entry *register_class_SysvSemaphore(void) INIT_CLASS_ENTRY(ce, "SysvSemaphore", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_SysvSemaphore_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_SysvSemaphore_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_SysvSemaphore_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_SysvSemaphore_0, true); + zend_string *attribute_NonInstantiableClass_class_SysvSemaphore_0_arg0_str = zend_string_init("Cannot directly construct SysvSemaphore, use sem_get() instead", strlen("Cannot directly construct SysvSemaphore, use sem_get() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_SysvSemaphore_0->args[0].value, attribute_NonInstantiableClass_class_SysvSemaphore_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/sysvshm/sysvshm.c b/ext/sysvshm/sysvshm.c index 96324e67c44d..1f018a4d4f70 100644 --- a/ext/sysvshm/sysvshm.c +++ b/ext/sysvshm/sysvshm.c @@ -23,10 +23,11 @@ #include #include "php_sysvshm.h" -#include "sysvshm_arginfo.h" #include "ext/standard/info.h" #include "ext/standard/php_var.h" #include "zend_smart_str.h" +#include "zend_attributes.h" +#include "sysvshm_arginfo.h" /* SysvSharedMemory class */ @@ -48,11 +49,6 @@ static zend_object *sysvshm_create_object(zend_class_entry *class_type) { return &intern->std; } -static zend_function *sysvshm_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct SysvSharedMemory, use shm_attach() instead"); - return NULL; -} - static void sysvshm_free_obj(zend_object *object) { sysvshm_shm *sysvshm = sysvshm_from_obj(object); @@ -102,7 +98,6 @@ PHP_MINIT_FUNCTION(sysvshm) memcpy(&sysvshm_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); sysvshm_object_handlers.offset = offsetof(sysvshm_shm, std); sysvshm_object_handlers.free_obj = sysvshm_free_obj; - sysvshm_object_handlers.get_constructor = sysvshm_get_constructor; sysvshm_object_handlers.clone_obj = NULL; sysvshm_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/sysvshm/sysvshm.stub.php b/ext/sysvshm/sysvshm.stub.php index c89f67bc068a..1a9e74166e3a 100644 --- a/ext/sysvshm/sysvshm.stub.php +++ b/ext/sysvshm/sysvshm.stub.php @@ -6,6 +6,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct SysvSharedMemory, use shm_attach() instead")] final class SysvSharedMemory { } diff --git a/ext/sysvshm/sysvshm_arginfo.h b/ext/sysvshm/sysvshm_arginfo.h index aade5b8276a4..5ddc693f2bbe 100644 --- a/ext/sysvshm/sysvshm_arginfo.h +++ b/ext/sysvshm/sysvshm_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit sysvshm.stub.php instead. - * Stub hash: 792c695a705678a3779d62cef8a5136069f98dee */ + * Stub hash: d5f2cf0533fa36b27345e610061cc4abf456da65 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_shm_attach, 0, 1, SysvSharedMemory, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, key, IS_LONG, 0) @@ -59,5 +59,13 @@ static zend_class_entry *register_class_SysvSharedMemory(void) INIT_CLASS_ENTRY(ce, "SysvSharedMemory", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_SysvSharedMemory_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_SysvSharedMemory_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_SysvSharedMemory_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_SysvSharedMemory_0, true); + zend_string *attribute_NonInstantiableClass_class_SysvSharedMemory_0_arg0_str = zend_string_init("Cannot directly construct SysvSharedMemory, use shm_attach() instead", strlen("Cannot directly construct SysvSharedMemory, use shm_attach() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_SysvSharedMemory_0->args[0].value, attribute_NonInstantiableClass_class_SysvSharedMemory_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 5bc502f2ef76..1fe8bea4bb3b 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -121,7 +121,6 @@ static PHP_GINIT_FUNCTION(xml); static zend_object *xml_parser_create_object(zend_class_entry *class_type); static void xml_parser_free_obj(zend_object *object); static HashTable *xml_parser_get_gc(zend_object *object, zval **table, int *n); -static zend_function *xml_parser_get_constructor(zend_object *object); static zend_string *xml_utf8_decode(const XML_Char *, size_t, const XML_Char *); inline static unsigned short xml_encode_iso_8859_1(unsigned char); @@ -225,7 +224,6 @@ PHP_MINIT_FUNCTION(xml) xml_parser_object_handlers.offset = offsetof(xml_parser, std); xml_parser_object_handlers.free_obj = xml_parser_free_obj; xml_parser_object_handlers.get_gc = xml_parser_get_gc; - xml_parser_object_handlers.get_constructor = xml_parser_get_constructor; xml_parser_object_handlers.clone_obj = NULL; xml_parser_object_handlers.compare = zend_objects_not_comparable; @@ -429,11 +427,6 @@ static HashTable *xml_parser_get_gc(zend_object *object, zval **table, int *n) return zend_std_get_properties(object); } -static zend_function *xml_parser_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct XMLParser, use xml_parser_create() or xml_parser_create_ns() instead"); - return NULL; -} - /* This is always called to simplify the mess to deal with BC breaks, but only set a new handler if it is initialized */ static void xml_set_handler(zend_fcall_info_cache *const parser_handler, const zend_fcall_info_cache *const fn) { diff --git a/ext/xml/xml.stub.php b/ext/xml/xml.stub.php index f589c3b2c8f1..343be4929572 100644 --- a/ext/xml/xml.stub.php +++ b/ext/xml/xml.stub.php @@ -202,6 +202,7 @@ function xml_parser_get_option(XMLParser $parser, int $option): string|int|bool * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct XMLParser, use xml_parser_create() or xml_parser_create_ns() instead")] final class XMLParser { } diff --git a/ext/xml/xml_arginfo.h b/ext/xml/xml_arginfo.h index 96430aef12bd..e515be880af5 100644 --- a/ext/xml/xml_arginfo.h +++ b/ext/xml/xml_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit xml.stub.php instead. - * Stub hash: c7838fb209d601be280dfdebfd135906afa36e8c */ + * Stub hash: 9e143434b552f9360bbfef607bff65fd3511add0 */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_xml_parser_create, 0, 0, XMLParser, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, encoding, IS_STRING, 1, "null") @@ -185,5 +185,13 @@ static zend_class_entry *register_class_XMLParser(void) INIT_CLASS_ENTRY(ce, "XMLParser", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_XMLParser_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_XMLParser_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_XMLParser_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_XMLParser_0, true); + zend_string *attribute_NonInstantiableClass_class_XMLParser_0_arg0_str = zend_string_init("Cannot directly construct XMLParser, use xml_parser_create() or xml_parser_create_ns() instead", strlen("Cannot directly construct XMLParser, use xml_parser_create() or xml_parser_create_ns() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_XMLParser_0->args[0].value, attribute_NonInstantiableClass_class_XMLParser_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/ext/zend_test/tests/zend_object_init_with_constructor.phpt b/ext/zend_test/tests/zend_object_init_with_constructor.phpt index 65b111447f0b..9a138e5ea531 100644 --- a/ext/zend_test/tests/zend_object_init_with_constructor.phpt +++ b/ext/zend_test/tests/zend_object_init_with_constructor.phpt @@ -58,6 +58,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("_ZendTestTrait"); @@ -65,6 +66,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("ZendTestUnitEnum"); @@ -72,6 +74,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("AbstractClass"); @@ -79,6 +82,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("SysvMessageQueue"); @@ -86,6 +90,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("PrivateUser"); @@ -93,6 +98,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("ThrowingUser"); @@ -100,6 +106,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } echo "Testing param passing\n"; @@ -109,6 +116,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("TestUserWithConstructorArgs", "str", 5); @@ -116,6 +124,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } try { $o = zend_object_init_with_constructor("TestUserWithConstructorArgs", 5, string_param: "str", unused_param: 15.3); @@ -123,6 +132,7 @@ try { unset($o); } catch (\Throwable $e) { echo $e::class, ': ', $e->getMessage(), PHP_EOL; + unset($e); } $o = zend_object_init_with_constructor("TestUserWithConstructorArgs", 5, string_param: "str"); diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c index 3b987fa45e48..347e19b1eeb1 100644 --- a/ext/zlib/zlib.c +++ b/ext/zlib/zlib.c @@ -20,6 +20,7 @@ #include #endif +#include "zend_attributes.h" #include "php.h" #include "SAPI.h" #include "php_ini.h" @@ -62,11 +63,6 @@ static zend_object *inflate_context_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *inflate_context_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct InflateContext, use inflate_init() instead"); - return NULL; -} - static void inflate_context_free_obj(zend_object *object) { php_zlib_context *intern = inflate_context_from_obj(object); @@ -100,11 +96,6 @@ static zend_object *deflate_context_create_object(zend_class_entry *class_type) return &intern->std; } -static zend_function *deflate_context_get_constructor(zend_object *object) { - zend_throw_error(NULL, "Cannot directly construct DeflateContext, use deflate_init() instead"); - return NULL; -} - static void deflate_context_free_obj(zend_object *object) { php_zlib_context *intern = deflate_context_from_obj(object); @@ -1357,7 +1348,6 @@ static PHP_MINIT_FUNCTION(zlib) memcpy(&inflate_context_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); inflate_context_object_handlers.offset = offsetof(php_zlib_context, std); inflate_context_object_handlers.free_obj = inflate_context_free_obj; - inflate_context_object_handlers.get_constructor = inflate_context_get_constructor; inflate_context_object_handlers.clone_obj = NULL; inflate_context_object_handlers.compare = zend_objects_not_comparable; @@ -1368,7 +1358,6 @@ static PHP_MINIT_FUNCTION(zlib) memcpy(&deflate_context_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); deflate_context_object_handlers.offset = offsetof(php_zlib_context, std); deflate_context_object_handlers.free_obj = deflate_context_free_obj; - deflate_context_object_handlers.get_constructor = deflate_context_get_constructor; deflate_context_object_handlers.clone_obj = NULL; deflate_context_object_handlers.compare = zend_objects_not_comparable; diff --git a/ext/zlib/zlib.stub.php b/ext/zlib/zlib.stub.php index 06f0f6d3ae8e..f6e6e231a97d 100644 --- a/ext/zlib/zlib.stub.php +++ b/ext/zlib/zlib.stub.php @@ -147,6 +147,7 @@ * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct InflateContext, use inflate_init() instead")] final class InflateContext { } @@ -155,6 +156,7 @@ final class InflateContext * @strict-properties * @not-serializable */ +#[\NonInstantiableClass("Cannot directly construct DeflateContext, use deflate_init() instead")] final class DeflateContext { } diff --git a/ext/zlib/zlib_arginfo.h b/ext/zlib/zlib_arginfo.h index 22605924b8b1..1dd6f1410c0a 100644 --- a/ext/zlib/zlib_arginfo.h +++ b/ext/zlib/zlib_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit zlib.stub.php instead. - * Stub hash: 4c5bea6d9f290c244c7bb27c77fe8007d43a40db */ + * Stub hash: 58b0352e30109a3207350f0bc8932304794cb169 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_ob_gzhandler, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) @@ -234,6 +234,14 @@ static zend_class_entry *register_class_InflateContext(void) INIT_CLASS_ENTRY(ce, "InflateContext", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_InflateContext_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_InflateContext_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_InflateContext_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_InflateContext_0, true); + zend_string *attribute_NonInstantiableClass_class_InflateContext_0_arg0_str = zend_string_init("Cannot directly construct InflateContext, use inflate_init() instead", strlen("Cannot directly construct InflateContext, use inflate_init() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_InflateContext_0->args[0].value, attribute_NonInstantiableClass_class_InflateContext_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } @@ -244,5 +252,13 @@ static zend_class_entry *register_class_DeflateContext(void) INIT_CLASS_ENTRY(ce, "DeflateContext", NULL); class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); + zend_string *attribute_name_NonInstantiableClass_class_DeflateContext_0 = zend_string_init_interned("NonInstantiableClass", sizeof("NonInstantiableClass") - 1, true); + zend_attribute *attribute_NonInstantiableClass_class_DeflateContext_0 = zend_add_class_attribute(class_entry, attribute_name_NonInstantiableClass_class_DeflateContext_0, 1); + zend_string_release_ex(attribute_name_NonInstantiableClass_class_DeflateContext_0, true); + zend_string *attribute_NonInstantiableClass_class_DeflateContext_0_arg0_str = zend_string_init("Cannot directly construct DeflateContext, use deflate_init() instead", strlen("Cannot directly construct DeflateContext, use deflate_init() instead"), 1); + ZVAL_STR(&attribute_NonInstantiableClass_class_DeflateContext_0->args[0].value, attribute_NonInstantiableClass_class_DeflateContext_0_arg0_str); + + class_entry->constructor = (zend_function *) &zend_non_instantiable_constructor; + return class_entry; } diff --git a/sapi/fuzzer/fuzzer-sapi.c b/sapi/fuzzer/fuzzer-sapi.c index 96fe75ab7a8a..fd8f364de2bf 100644 --- a/sapi/fuzzer/fuzzer-sapi.c +++ b/sapi/fuzzer/fuzzer-sapi.c @@ -124,12 +124,6 @@ static sapi_module_struct fuzzer_module = { STANDARD_SAPI_MODULE_PROPERTIES }; -static ZEND_COLD zend_function *disable_class_get_constructor_handler(zend_object *obj) /* {{{ */ -{ - zend_throw_error(NULL, "Cannot construct class %s, as it is disabled", ZSTR_VAL(obj->ce->name)); - return NULL; -} - static void fuzzer_disable_classes(void) { /* Overwrite built-in constructor for InfiniteIterator as it @@ -137,10 +131,7 @@ static void fuzzer_disable_classes(void) /* Lowercase as this is how the CE as stored */ zend_class_entry *InfiniteIterator_class = zend_hash_str_find_ptr(CG(class_table), "infiniteiterator", strlen("infiniteiterator")); - static zend_object_handlers handlers; - memcpy(&handlers, InfiniteIterator_class->default_object_handlers, sizeof(handlers)); - handlers.get_constructor = disable_class_get_constructor_handler; - InfiniteIterator_class->default_object_handlers = &handlers; + zend_class_entry *InfiniteIterator_class->constructor = (zend_function *) &zend_non_instantiable_constructor; } int fuzzer_init_php(const char *extra_ini)