diff --git a/Zend/tests/arginfo_zpp_mismatch.inc b/Zend/tests/arginfo_zpp_mismatch.inc index 2eb8905f5d4a1..aa362a2fac4ca 100644 --- a/Zend/tests/arginfo_zpp_mismatch.inc +++ b/Zend/tests/arginfo_zpp_mismatch.inc @@ -15,6 +15,7 @@ function skipFunction($function): bool { || $function === 'zend_test_array_return' || $function === 'zend_test_crash' || $function === 'zend_leak_bytes' + || $function === 'zend_test_use_internal_traits_not_trait' /* mess with output */ || (is_string($function) && str_starts_with($function, 'ob_')) || $function === 'output_add_rewrite_var' diff --git a/Zend/zend_API.h b/Zend/zend_API.h index e56ded4e8f1b5..f756e2b0bf55b 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -392,6 +392,7 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(const zend_class_entr ZEND_API zend_class_entry *zend_register_internal_class_with_flags(const zend_class_entry *class_entry, zend_class_entry *parent_ce, uint32_t flags); ZEND_API zend_class_entry *zend_register_internal_interface(const zend_class_entry *orig_class_entry); ZEND_API void zend_class_implements(zend_class_entry *class_entry, int num_interfaces, ...); +ZEND_API void zend_class_use_internal_traits(zend_class_entry *class_entry, int num_traits, ...); ZEND_API zend_result zend_register_class_alias_ex(const char *name, size_t name_len, zend_class_entry *ce, bool persistent); diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 69f3be91fa065..f6034e83f6062 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -2401,7 +2401,11 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_ } } - if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) { + if (ce->type == ZEND_INTERNAL_CLASS) { + ZEND_ASSERT(fn->type == ZEND_INTERNAL_FUNCTION); + new_fn = (zend_function*)(uintptr_t)malloc(sizeof(zend_internal_function)); + memcpy(new_fn, fn, sizeof(zend_internal_function)); + } else if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) { new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function)); memcpy(new_fn, fn, sizeof(zend_internal_function)); new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED; @@ -2820,7 +2824,11 @@ static void zend_do_traits_constant_binding(zend_class_entry *ce, zend_class_ent if (do_trait_constant_check(ce, constant, constant_name, traits, i)) { zend_class_constant *ct = NULL; - ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant)); + if (ce->type == ZEND_INTERNAL_CLASS) { + ct = malloc(sizeof(zend_class_constant)); + } else { + ct = zend_arena_alloc(&CG(arena),sizeof(zend_class_constant)); + } memcpy(ct, constant, sizeof(zend_class_constant)); constant = ct; @@ -2999,6 +3007,56 @@ static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_ent } /* }}} */ +ZEND_API void zend_class_use_internal_traits(zend_class_entry *class_entry, int num_traits, ...) /* {{{ */ +{ + zend_class_entry *trait_entry; + va_list trait_list; + zend_class_entry **traits; + zend_function *fn; + + ZEND_ASSERT(class_entry->ce_flags & ZEND_ACC_LINKED); + ZEND_ASSERT(num_traits >= 0); + + if (UNEXPECTED(num_traits == 0)) { + return; + } + + traits = safe_emalloc(num_traits, sizeof(zend_class_entry *), 0); + class_entry->trait_names = safe_pemalloc(num_traits, sizeof(zend_class_name), 0, 1); + class_entry->num_traits = num_traits; + + va_start(trait_list, num_traits); + for (int i = 0; i < num_traits; i++) { + trait_entry = va_arg(trait_list, zend_class_entry *); + class_entry->trait_names[i].name = zend_string_copy(trait_entry->name); + class_entry->trait_names[i].lc_name = zend_string_tolower_ex(zend_string_copy(trait_entry->name), 1); + + if (UNEXPECTED(!(trait_entry->ce_flags & ZEND_ACC_TRAIT))) { + efree(traits); + zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot use %s - it is not a trait", + ZSTR_VAL(class_entry->name), ZSTR_VAL(trait_entry->name)); + } + traits[i] = trait_entry; + } + va_end(trait_list); + + bool contains_abstract_methods = false; + zend_do_traits_method_binding(class_entry, traits, NULL, NULL, false, &contains_abstract_methods); + + zend_do_traits_constant_binding(class_entry, traits); + + zend_do_traits_property_binding(class_entry, traits); + + ZEND_HASH_MAP_FOREACH_PTR(&class_entry->function_table, fn) { + zend_fixup_trait_method(fn, class_entry); + } ZEND_HASH_FOREACH_END(); + + efree(traits); + + /* TODO: Verify abstract trait method implementation requirements are enforced. */ +} +/* }}} */ + #define MAX_ABSTRACT_INFO_CNT 3 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s" #define DISPLAY_ABSTRACT_FN(idx) \ diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 35de02b557298..944e860483154 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -486,7 +486,7 @@ ZEND_API void destroy_zend_class(zval *zv) zend_string_release_ex(ce->name, 1); ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) { - if (fn->common.scope == ce) { + if (fn->common.scope == ce && !(fn->common.fn_flags & ZEND_ACC_TRAIT_CLONE)) { zend_free_internal_arg_info(&fn->internal_function, true); if (fn->common.attributes) { @@ -536,6 +536,13 @@ ZEND_API void destroy_zend_class(zval *zv) if (ce->attributes) { zend_hash_release(ce->attributes); } + if (ce->num_traits > 0) { + for (uint32_t i = 0; i < ce->num_traits; i++) { + zend_string_release(ce->trait_names[i].name); + zend_string_release(ce->trait_names[i].lc_name); + } + free(ce->trait_names); + } free(ce); break; } diff --git a/build/gen_stub.php b/build/gen_stub.php index ce1a238666109..fa78a0ad28cc1 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -13,6 +13,7 @@ use PhpParser\Node\Stmt\Enum_; use PhpParser\Node\Stmt\Interface_; use PhpParser\Node\Stmt\Trait_; +use PhpParser\Node\Stmt\TraitUse; use PhpParser\PrettyPrinter\Standard; use PhpParser\PrettyPrinterAbstract; @@ -3300,6 +3301,7 @@ class ClassInfo { * @param AttributeInfo[] $attributes * @param Name[] $extends * @param Name[] $implements + * @param Name[] $uses * @param ConstInfo[] $constInfos * @param PropertyInfo[] $propertyInfos * @param FuncInfo[] $funcInfos @@ -3318,6 +3320,7 @@ public function __construct( private bool $isNotSerializable, private readonly array $extends, private readonly array $implements, + private readonly array $uses, public /* readonly */ array $constInfos, private /* readonly */ array $propertyInfos, public array $funcInfos, @@ -3337,6 +3340,9 @@ public function getRegistration(array $allConstInfos): string foreach ($this->implements as $implements) { $params[] = "zend_class_entry *class_entry_" . implode("_", $implements->getParts()); } + foreach ($this->uses as $use) { + $params[] = "zend_class_entry *class_entry_" . implode("_", $use->getParts()); + } $escapedName = implode("_", $this->name->getParts()); @@ -3434,6 +3440,17 @@ function (Name $item) { $code .= "\tzend_class_implements(class_entry, " . count($implements) . ", " . implode(", ", $implements) . ");\n"; } + $traits = array_map( + function (Name $item) { + return "class_entry_" . implode("_", $item->getParts()); + }, + $this->uses + ); + + if (!empty($traits)) { + $code .= "\tzend_class_use_internal_traits(class_entry, " . count($traits) . ", " . implode(", ", $traits) . ");\n"; + } + if ($this->alias) { $code .= "\tzend_register_class_alias(\"" . str_replace("\\", "\\\\", $this->alias) . "\", class_entry);\n"; } @@ -4299,6 +4316,7 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri $propertyInfos = []; $methodInfos = []; $enumCaseInfos = []; + $traitUses = []; foreach ($stmt->stmts as $classStmt) { $cond = self::handlePreprocessorConditions($conds, $classStmt); if ($classStmt instanceof Stmt\Nop) { @@ -4360,6 +4378,10 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri $classStmt->expr, $classStmt->expr ? $prettyPrinter->prettyPrintExpr($classStmt->expr) : null, ); + } else if ($classStmt instanceof TraitUse) { + foreach ($classStmt->traits as $trait) { + $traitUses[] = $trait; + } } else { throw new Exception("Not implemented {$classStmt->getType()}"); } @@ -4372,6 +4394,7 @@ private function handleStatements(array $stmts, PrettyPrinterAbstract $prettyPri $propertyInfos, $methodInfos, $enumCaseInfos, + $traitUses, $cond, $this->getMinimumPhpVersionIdCompatibility(), $this->isUndocumentable @@ -5055,6 +5078,7 @@ function parseProperty( * @param PropertyInfo[] $properties * @param FuncInfo[] $methods * @param EnumCaseInfo[] $enumCases + * @param Name[] $traitUses */ function parseClass( Name $name, @@ -5063,6 +5087,7 @@ function parseClass( array $properties, array $methods, array $enumCases, + array $traitUses, ?string $cond, ?int $minimumPhpVersionIdCompatibility, bool $isUndocumentable @@ -5134,6 +5159,7 @@ function parseClass( $isNotSerializable, $extends, $implements, + $traitUses, $consts, $properties, $methods, diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 7ab2272dd1684..6c4e2f74cd665 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -57,6 +57,10 @@ static zend_class_entry *zend_test_child_class; static zend_class_entry *zend_test_gen_stub_flag_compatibility_test; static zend_class_entry *zend_attribute_test_class; static zend_class_entry *zend_test_trait; +static zend_class_entry *zend_test_trait_for_internal_class; +static zend_class_entry *zend_test_class_with_trait; +static zend_class_entry *zend_test_not_a_trait_for_internal_traits; +static zend_class_entry *zend_test_internal_traits_driver; static zend_class_entry *zend_test_attribute; static zend_class_entry *zend_test_repeatable_attribute; static zend_class_entry *zend_test_parameter_attribute; @@ -1234,6 +1238,26 @@ static ZEND_METHOD(_ZendTestTrait, testMethod) RETURN_TRUE; } +static ZEND_METHOD(_ZendTestTraitForInternalClass, traitMethod) +{ + ZEND_PARSE_PARAMETERS_NONE(); + RETURN_LONG(789); +} + +static ZEND_FUNCTION(zend_test_use_internal_traits_zero) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_class_use_internal_traits(zend_test_internal_traits_driver, 0); +} + +static ZEND_FUNCTION(zend_test_use_internal_traits_not_trait) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_class_use_internal_traits(zend_test_internal_traits_driver, 1, zend_test_not_a_trait_for_internal_traits); +} + static ZEND_METHOD(ZendTestNS_Foo, method) { ZEND_PARSE_PARAMETERS_NONE(); @@ -1536,6 +1560,10 @@ PHP_MINIT_FUNCTION(zend_test) zend_attribute_test_class = register_class_ZendAttributeTest(); zend_test_trait = register_class__ZendTestTrait(); + zend_test_trait_for_internal_class = register_class__ZendTestTraitForInternalClass(); + zend_test_class_with_trait = register_class__ZendTestClassWithTrait(zend_test_trait_for_internal_class); + zend_test_not_a_trait_for_internal_traits = register_class__ZendTestNotATraitForInternalTraits(); + zend_test_internal_traits_driver = register_class__ZendTestInternalTraitsDriver(); register_test_symbols(module_number); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index e102082c6a95c..cfa3dfeee2b03 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -35,6 +35,28 @@ interface _ZendTestInterface public const DUMMY = 0; } + trait _ZendTestTraitForInternalClass + { + /** @var int */ + public const ZEND_TRAIT_CONST = 123; + + public int $traitProp = 456; + + public function traitMethod(): int {} + } + + class _ZendTestClassWithTrait + { + use _ZendTestTraitForInternalClass; + } + + class _ZendTestNotATraitForInternalTraits {} + + class _ZendTestInternalTraitsDriver {} + + function zend_test_use_internal_traits_zero(): void {} + function zend_test_use_internal_traits_not_trait(): void {} + /** @alias _ZendTestClassAlias */ class _ZendTestClass implements _ZendTestInterface { public const mixed TYPED_CLASS_CONST1 = []; diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 30297234fc873..4972a4e4aa51a 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,7 +1,12 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 46178f5fa88681da91d831250f2f00c45e914624 + * Stub hash: 7dad50cbf54bd7543565c10e433df73ba48af5a2 * Has decl header: yes */ +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_use_internal_traits_zero, 0, 0, IS_VOID, 0) +ZEND_END_ARG_INFO() + +#define arginfo_zend_test_use_internal_traits_not_trait arginfo_zend_test_use_internal_traits_zero + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_trigger_bailout, 0, 0, IS_NEVER, 0) ZEND_END_ARG_INFO() @@ -11,8 +16,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_nullable_array_return, 0, 0, IS_ARRAY, 1) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_void_return, 0, 0, IS_VOID, 0) -ZEND_END_ARG_INFO() +#define arginfo_zend_test_void_return arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_compile_string, 0, 3, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, source_string, IS_STRING, 0) @@ -24,16 +28,16 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_deprecated, 0, 0, IS_V ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg, IS_MIXED, 0, "null") ZEND_END_ARG_INFO() -#define arginfo_zend_test_deprecated_attr arginfo_zend_test_void_return +#define arginfo_zend_test_deprecated_attr arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_nodiscard, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() #define arginfo_zend_test_deprecated_nodiscard arginfo_zend_test_nodiscard -#define arginfo_zend_test_aliased arginfo_zend_test_void_return +#define arginfo_zend_test_aliased arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_deprecated_aliased arginfo_zend_test_void_return +#define arginfo_zend_test_deprecated_aliased arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_create_unterminated_string, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0) @@ -100,7 +104,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_parameter_with_attribu ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0) ZEND_END_ARG_INFO() -#define arginfo_zend_test_attribute_with_named_argument arginfo_zend_test_void_return +#define arginfo_zend_test_attribute_with_named_argument arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_get_current_func_name, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -189,7 +193,7 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_compile_to_ast arginfo_zend_create_unterminated_string -#define arginfo_zend_test_gh18756 arginfo_zend_test_void_return +#define arginfo_zend_test_gh18756 arginfo_zend_test_use_internal_traits_zero #define arginfo_zend_test_opcache_preloading arginfo_zend_test_is_pcre_bundled @@ -198,23 +202,25 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_uri_parser, 0, 2, IS_A ZEND_ARG_TYPE_INFO(0, parser, IS_STRING, 0) ZEND_END_ARG_INFO() -#define arginfo_zend_test_gh19792 arginfo_zend_test_void_return +#define arginfo_zend_test_gh19792 arginfo_zend_test_use_internal_traits_zero #define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_is_pcre_bundled -#define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return +#define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_namespaced_aliased_func arginfo_zend_test_void_return +#define arginfo_ZendTestNS2_namespaced_aliased_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_namespaced_deprecated_aliased_func arginfo_zend_test_void_return +#define arginfo_ZendTestNS2_namespaced_deprecated_aliased_func arginfo_zend_test_use_internal_traits_zero #define arginfo_ZendTestNS2_ZendSubNS_namespaced_func arginfo_zend_test_is_pcre_bundled -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_func arginfo_zend_test_void_return +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_aliased_func arginfo_zend_test_void_return +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_aliased_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func arginfo_zend_test_void_return +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func arginfo_zend_test_use_internal_traits_zero + +#define arginfo_class__ZendTestTraitForInternalClass_traitMethod arginfo_zend_test_nodiscard #define arginfo_class__ZendTestClass_is_object arginfo_zend_test_nodiscard @@ -264,9 +270,9 @@ ZEND_END_ARG_INFO() #define arginfo_class_ZendTestChildClassWithMethodWithParameterAttribute_override arginfo_zend_test_parameter_with_attribute -#define arginfo_class_ZendTestForbidDynamicCall_call arginfo_zend_test_void_return +#define arginfo_class_ZendTestForbidDynamicCall_call arginfo_zend_test_use_internal_traits_zero -#define arginfo_class_ZendTestForbidDynamicCall_callStatic arginfo_zend_test_void_return +#define arginfo_class_ZendTestForbidDynamicCall_callStatic arginfo_zend_test_use_internal_traits_zero #if (PHP_VERSION_ID >= 80100) ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_ZendTestNS_Foo_method, 0, 0, IS_LONG, 0) @@ -281,10 +287,12 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_ZendTestNS_NotUnlikelyCompileError_method, 0, 0, ZendTestNS\\\116otUnlikelyCompileError, 1) ZEND_END_ARG_INFO() -#define arginfo_class_ZendTestNS2_Foo_method arginfo_zend_test_void_return +#define arginfo_class_ZendTestNS2_Foo_method arginfo_zend_test_use_internal_traits_zero -#define arginfo_class_ZendTestNS2_ZendSubNS_Foo_method arginfo_zend_test_void_return +#define arginfo_class_ZendTestNS2_ZendSubNS_Foo_method arginfo_zend_test_use_internal_traits_zero +static ZEND_FUNCTION(zend_test_use_internal_traits_zero); +static ZEND_FUNCTION(zend_test_use_internal_traits_not_trait); static ZEND_FUNCTION(zend_trigger_bailout); static ZEND_FUNCTION(zend_test_array_return); static ZEND_FUNCTION(zend_test_nullable_array_return); @@ -349,6 +357,7 @@ static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_deprecated_func); +static ZEND_METHOD(_ZendTestTraitForInternalClass, traitMethod); static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); static ZEND_METHOD(_ZendTestClass, returnsStatic); @@ -375,6 +384,8 @@ static ZEND_METHOD(ZendTestNS2_Foo, method); static ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo, method); static const zend_function_entry ext_functions[] = { + ZEND_FE(zend_test_use_internal_traits_zero, arginfo_zend_test_use_internal_traits_zero) + ZEND_FE(zend_test_use_internal_traits_not_trait, arginfo_zend_test_use_internal_traits_not_trait) ZEND_FE(zend_trigger_bailout, arginfo_zend_trigger_bailout) ZEND_FE(zend_test_array_return, arginfo_zend_test_array_return) #if (PHP_VERSION_ID >= 80400) @@ -528,6 +539,11 @@ static const zend_function_entry ext_functions[] = { ZEND_FE_END }; +static const zend_function_entry class__ZendTestTraitForInternalClass_methods[] = { + ZEND_ME(_ZendTestTraitForInternalClass, traitMethod, arginfo_class__ZendTestTraitForInternalClass_traitMethod, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static const zend_function_entry class__ZendTestClass_methods[] = { ZEND_ME(_ZendTestClass, is_object, arginfo_class__ZendTestClass_is_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(_ZendTestClass, __toString, arginfo_class__ZendTestClass___toString, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) @@ -698,6 +714,76 @@ static zend_class_entry *register_class__ZendTestInterface(void) return class_entry; } +static zend_class_entry *register_class__ZendTestTraitForInternalClass(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestTraitForInternalClass", class__ZendTestTraitForInternalClass_methods); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_TRAIT); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_TRAIT; +#endif + + zval const_ZEND_TRAIT_CONST_value; + ZVAL_LONG(&const_ZEND_TRAIT_CONST_value, 123); + zend_string *const_ZEND_TRAIT_CONST_name = zend_string_init_interned("ZEND_TRAIT_CONST", sizeof("ZEND_TRAIT_CONST") - 1, true); + zend_declare_class_constant_ex(class_entry, const_ZEND_TRAIT_CONST_name, &const_ZEND_TRAIT_CONST_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release_ex(const_ZEND_TRAIT_CONST_name, true); + + zval property_traitProp_default_value; + ZVAL_LONG(&property_traitProp_default_value, 456); + zend_string *property_traitProp_name = zend_string_init("traitProp", sizeof("traitProp") - 1, true); + zend_declare_typed_property(class_entry, property_traitProp_name, &property_traitProp_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_LONG)); + zend_string_release_ex(property_traitProp_name, true); + + return class_entry; +} + +static zend_class_entry *register_class__ZendTestClassWithTrait(zend_class_entry *class_entry__ZendTestTraitForInternalClass) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestClassWithTrait", NULL); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); +#endif + zend_class_use_internal_traits(class_entry, 1, class_entry__ZendTestTraitForInternalClass); + + return class_entry; +} + +static zend_class_entry *register_class__ZendTestNotATraitForInternalTraits(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestNotATraitForInternalTraits", NULL); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); +#endif + + return class_entry; +} + +static zend_class_entry *register_class__ZendTestInternalTraitsDriver(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestInternalTraitsDriver", NULL); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); +#endif + + return class_entry; +} + static zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_entry__ZendTestInterface) { zend_class_entry ce, *class_entry; diff --git a/ext/zend_test/test_decl.h b/ext/zend_test/test_decl.h index ed0874f51e723..9a6a32f63a845 100644 --- a/ext/zend_test/test_decl.h +++ b/ext/zend_test/test_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 46178f5fa88681da91d831250f2f00c45e914624 */ + * Stub hash: 7dad50cbf54bd7543565c10e433df73ba48af5a2 */ -#ifndef ZEND_TEST_DECL_46178f5fa88681da91d831250f2f00c45e914624_H -#define ZEND_TEST_DECL_46178f5fa88681da91d831250f2f00c45e914624_H +#ifndef ZEND_TEST_DECL_7dad50cbf54bd7543565c10e433df73ba48af5a2_H +#define ZEND_TEST_DECL_7dad50cbf54bd7543565c10e433df73ba48af5a2_H typedef enum zend_enum_ZendTestUnitEnum { ZEND_ENUM_ZendTestUnitEnum_Foo = 1, @@ -27,4 +27,4 @@ typedef enum zend_enum_ZendTestEnumWithInterface { ZEND_ENUM_ZendTestEnumWithInterface_Bar = 2, } zend_enum_ZendTestEnumWithInterface; -#endif /* ZEND_TEST_DECL_46178f5fa88681da91d831250f2f00c45e914624_H */ +#endif /* ZEND_TEST_DECL_7dad50cbf54bd7543565c10e433df73ba48af5a2_H */ diff --git a/ext/zend_test/test_legacy_arginfo.h b/ext/zend_test/test_legacy_arginfo.h index 3dcdad8ff6c7e..5ded738d209a3 100644 --- a/ext/zend_test/test_legacy_arginfo.h +++ b/ext/zend_test/test_legacy_arginfo.h @@ -1,15 +1,19 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 46178f5fa88681da91d831250f2f00c45e914624 + * Stub hash: 7dad50cbf54bd7543565c10e433df73ba48af5a2 * Has decl header: yes */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_trigger_bailout, 0, 0, 0) +ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_use_internal_traits_zero, 0, 0, 0) ZEND_END_ARG_INFO() -#define arginfo_zend_test_array_return arginfo_zend_trigger_bailout +#define arginfo_zend_test_use_internal_traits_not_trait arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_nullable_array_return arginfo_zend_trigger_bailout +#define arginfo_zend_trigger_bailout arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_void_return arginfo_zend_trigger_bailout +#define arginfo_zend_test_array_return arginfo_zend_test_use_internal_traits_zero + +#define arginfo_zend_test_nullable_array_return arginfo_zend_test_use_internal_traits_zero + +#define arginfo_zend_test_void_return arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_compile_string, 0, 0, 3) ZEND_ARG_INFO(0, source_string) @@ -21,15 +25,15 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_deprecated, 0, 0, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() -#define arginfo_zend_test_deprecated_attr arginfo_zend_trigger_bailout +#define arginfo_zend_test_deprecated_attr arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_nodiscard arginfo_zend_trigger_bailout +#define arginfo_zend_test_nodiscard arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_deprecated_nodiscard arginfo_zend_trigger_bailout +#define arginfo_zend_test_deprecated_nodiscard arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_aliased arginfo_zend_trigger_bailout +#define arginfo_zend_test_aliased arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_deprecated_aliased arginfo_zend_trigger_bailout +#define arginfo_zend_test_deprecated_aliased arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_create_unterminated_string, 0, 0, 1) ZEND_ARG_INFO(0, str) @@ -77,17 +81,17 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_weakmap_remove, 0, 0, 1) ZEND_ARG_INFO(0, object) ZEND_END_ARG_INFO() -#define arginfo_zend_weakmap_dump arginfo_zend_trigger_bailout +#define arginfo_zend_weakmap_dump arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_get_unit_enum arginfo_zend_trigger_bailout +#define arginfo_zend_get_unit_enum arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_parameter_with_attribute, 0, 0, 1) ZEND_ARG_INFO(0, parameter) ZEND_END_ARG_INFO() -#define arginfo_zend_test_attribute_with_named_argument arginfo_zend_trigger_bailout +#define arginfo_zend_test_attribute_with_named_argument arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_get_current_func_name arginfo_zend_trigger_bailout +#define arginfo_zend_get_current_func_name arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_call_method, 0, 0, 2) ZEND_ARG_INFO(0, obj_or_class) @@ -111,9 +115,9 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_zend_ini_parse_uquantity arginfo_zend_create_unterminated_string -#define arginfo_zend_test_zend_ini_str arginfo_zend_trigger_bailout +#define arginfo_zend_test_zend_ini_str arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_zstr_init_literal arginfo_zend_trigger_bailout +#define arginfo_zend_test_zstr_init_literal arginfo_zend_test_use_internal_traits_zero #if defined(ZEND_CHECK_STACK_LIMIT) ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_zend_call_stack_get, 0, 0, 0) @@ -126,7 +130,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_is_string_marked_as_valid_utf8, 0, 0, 1 ZEND_ARG_INFO(0, string) ZEND_END_ARG_INFO() -#define arginfo_zend_get_map_ptr_last arginfo_zend_trigger_bailout +#define arginfo_zend_get_map_ptr_last arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_crash, 0, 0, 0) ZEND_ARG_INFO(0, message) @@ -136,16 +140,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_fill_packed_array, 0, 0, 1) ZEND_ARG_INFO(1, array) ZEND_END_ARG_INFO() -#define arginfo_zend_test_create_throwing_resource arginfo_zend_trigger_bailout +#define arginfo_zend_test_create_throwing_resource arginfo_zend_test_use_internal_traits_zero -#define arginfo_get_open_basedir arginfo_zend_trigger_bailout +#define arginfo_get_open_basedir arginfo_zend_test_use_internal_traits_zero #if defined(HAVE_LIBXML) && !defined(PHP_WIN32) ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_override_libxml_global_state, 0, 0, 0) ZEND_END_ARG_INFO() #endif -#define arginfo_zend_test_is_pcre_bundled arginfo_zend_trigger_bailout +#define arginfo_zend_test_is_pcre_bundled arginfo_zend_test_use_internal_traits_zero #if defined(PHP_WIN32) ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_set_fmode, 0, 0, 1) @@ -165,40 +169,42 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_compile_to_ast arginfo_zend_create_unterminated_string -#define arginfo_zend_test_gh18756 arginfo_zend_trigger_bailout +#define arginfo_zend_test_gh18756 arginfo_zend_test_use_internal_traits_zero -#define arginfo_zend_test_opcache_preloading arginfo_zend_trigger_bailout +#define arginfo_zend_test_opcache_preloading arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_test_uri_parser, 0, 0, 2) ZEND_ARG_INFO(0, uri) ZEND_ARG_INFO(0, parser) ZEND_END_ARG_INFO() -#define arginfo_zend_test_gh19792 arginfo_zend_trigger_bailout +#define arginfo_zend_test_gh19792 arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_namespaced_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_namespaced_aliased_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_namespaced_aliased_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_namespaced_deprecated_aliased_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_namespaced_deprecated_aliased_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_aliased_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_aliased_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func arginfo_zend_trigger_bailout +#define arginfo_ZendTestNS2_ZendSubNS_namespaced_deprecated_aliased_func arginfo_zend_test_use_internal_traits_zero -#define arginfo_class__ZendTestClass_is_object arginfo_zend_trigger_bailout +#define arginfo_class__ZendTestTraitForInternalClass_traitMethod arginfo_zend_test_use_internal_traits_zero -#define arginfo_class__ZendTestClass___toString arginfo_zend_trigger_bailout +#define arginfo_class__ZendTestClass_is_object arginfo_zend_test_use_internal_traits_zero -#define arginfo_class__ZendTestClass_returnsStatic arginfo_zend_trigger_bailout +#define arginfo_class__ZendTestClass___toString arginfo_zend_test_use_internal_traits_zero -#define arginfo_class__ZendTestClass_returnsThrowable arginfo_zend_trigger_bailout +#define arginfo_class__ZendTestClass_returnsStatic arginfo_zend_test_use_internal_traits_zero + +#define arginfo_class__ZendTestClass_returnsThrowable arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_class__ZendTestClass_variadicTest, 0, 0, 0) ZEND_ARG_VARIADIC_INFO(0, elements) @@ -215,11 +221,11 @@ ZEND_END_ARG_INFO() #define arginfo_class__ZendTestMagicCallForward___call arginfo_class__ZendTestMagicCall___call -#define arginfo_class__ZendTestChildClass_returnsThrowable arginfo_zend_trigger_bailout +#define arginfo_class__ZendTestChildClass_returnsThrowable arginfo_zend_test_use_internal_traits_zero -#define arginfo_class_ZendAttributeTest_testMethod arginfo_zend_trigger_bailout +#define arginfo_class_ZendAttributeTest_testMethod arginfo_zend_test_use_internal_traits_zero -#define arginfo_class__ZendTestTrait_testMethod arginfo_zend_trigger_bailout +#define arginfo_class__ZendTestTrait_testMethod arginfo_zend_test_use_internal_traits_zero #define arginfo_class_ZendTestAttributeWithArguments___construct arginfo_class__ZendTestClass_takesUnionType @@ -233,21 +239,23 @@ ZEND_END_ARG_INFO() #define arginfo_class_ZendTestChildClassWithMethodWithParameterAttribute_override arginfo_zend_test_parameter_with_attribute -#define arginfo_class_ZendTestForbidDynamicCall_call arginfo_zend_trigger_bailout +#define arginfo_class_ZendTestForbidDynamicCall_call arginfo_zend_test_use_internal_traits_zero -#define arginfo_class_ZendTestForbidDynamicCall_callStatic arginfo_zend_trigger_bailout +#define arginfo_class_ZendTestForbidDynamicCall_callStatic arginfo_zend_test_use_internal_traits_zero ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTestNS_Foo_method, 0, 0, 0) ZEND_END_ARG_INFO() -#define arginfo_class_ZendTestNS_UnlikelyCompileError_method arginfo_zend_trigger_bailout +#define arginfo_class_ZendTestNS_UnlikelyCompileError_method arginfo_zend_test_use_internal_traits_zero -#define arginfo_class_ZendTestNS_NotUnlikelyCompileError_method arginfo_zend_trigger_bailout +#define arginfo_class_ZendTestNS_NotUnlikelyCompileError_method arginfo_zend_test_use_internal_traits_zero -#define arginfo_class_ZendTestNS2_Foo_method arginfo_zend_trigger_bailout +#define arginfo_class_ZendTestNS2_Foo_method arginfo_zend_test_use_internal_traits_zero -#define arginfo_class_ZendTestNS2_ZendSubNS_Foo_method arginfo_zend_trigger_bailout +#define arginfo_class_ZendTestNS2_ZendSubNS_Foo_method arginfo_zend_test_use_internal_traits_zero +static ZEND_FUNCTION(zend_test_use_internal_traits_zero); +static ZEND_FUNCTION(zend_test_use_internal_traits_not_trait); static ZEND_FUNCTION(zend_trigger_bailout); static ZEND_FUNCTION(zend_test_array_return); static ZEND_FUNCTION(zend_test_nullable_array_return); @@ -312,6 +320,7 @@ static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_deprecated_func); +static ZEND_METHOD(_ZendTestTraitForInternalClass, traitMethod); static ZEND_METHOD(_ZendTestClass, is_object); static ZEND_METHOD(_ZendTestClass, __toString); static ZEND_METHOD(_ZendTestClass, returnsStatic); @@ -338,6 +347,8 @@ static ZEND_METHOD(ZendTestNS2_Foo, method); static ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo, method); static const zend_function_entry ext_functions[] = { + ZEND_FE(zend_test_use_internal_traits_zero, arginfo_zend_test_use_internal_traits_zero) + ZEND_FE(zend_test_use_internal_traits_not_trait, arginfo_zend_test_use_internal_traits_not_trait) ZEND_FE(zend_trigger_bailout, arginfo_zend_trigger_bailout) ZEND_FE(zend_test_array_return, arginfo_zend_test_array_return) ZEND_FE(zend_test_nullable_array_return, arginfo_zend_test_nullable_array_return) @@ -455,6 +466,11 @@ static const zend_function_entry ext_functions[] = { ZEND_FE_END }; +static const zend_function_entry class__ZendTestTraitForInternalClass_methods[] = { + ZEND_ME(_ZendTestTraitForInternalClass, traitMethod, arginfo_class__ZendTestTraitForInternalClass_traitMethod, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + static const zend_function_entry class__ZendTestClass_methods[] = { ZEND_ME(_ZendTestClass, is_object, arginfo_class__ZendTestClass_is_object, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(_ZendTestClass, __toString, arginfo_class__ZendTestClass___toString, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED) @@ -573,6 +589,76 @@ static zend_class_entry *register_class__ZendTestInterface(void) return class_entry; } +static zend_class_entry *register_class__ZendTestTraitForInternalClass(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestTraitForInternalClass", class__ZendTestTraitForInternalClass_methods); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_TRAIT); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); + class_entry->ce_flags |= ZEND_ACC_TRAIT; +#endif + + zval const_ZEND_TRAIT_CONST_value; + ZVAL_LONG(&const_ZEND_TRAIT_CONST_value, 123); + zend_string *const_ZEND_TRAIT_CONST_name = zend_string_init_interned("ZEND_TRAIT_CONST", sizeof("ZEND_TRAIT_CONST") - 1, true); + zend_declare_class_constant_ex(class_entry, const_ZEND_TRAIT_CONST_name, &const_ZEND_TRAIT_CONST_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release_ex(const_ZEND_TRAIT_CONST_name, true); + + zval property_traitProp_default_value; + ZVAL_LONG(&property_traitProp_default_value, 456); + zend_string *property_traitProp_name = zend_string_init("traitProp", sizeof("traitProp") - 1, true); + zend_declare_property_ex(class_entry, property_traitProp_name, &property_traitProp_default_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release_ex(property_traitProp_name, true); + + return class_entry; +} + +static zend_class_entry *register_class__ZendTestClassWithTrait(zend_class_entry *class_entry__ZendTestTraitForInternalClass) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestClassWithTrait", NULL); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); +#endif + zend_class_use_internal_traits(class_entry, 1, class_entry__ZendTestTraitForInternalClass); + + return class_entry; +} + +static zend_class_entry *register_class__ZendTestNotATraitForInternalTraits(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestNotATraitForInternalTraits", NULL); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); +#endif + + return class_entry; +} + +static zend_class_entry *register_class__ZendTestInternalTraitsDriver(void) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "_ZendTestInternalTraitsDriver", NULL); +#if (PHP_VERSION_ID >= 80400) + class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); +#else + class_entry = zend_register_internal_class_ex(&ce, NULL); +#endif + + return class_entry; +} + static zend_class_entry *register_class__ZendTestClass(zend_class_entry *class_entry__ZendTestInterface) { zend_class_entry ce, *class_entry; diff --git a/ext/zend_test/tests/internal_class_multiple_traits.phpt b/ext/zend_test/tests/internal_class_multiple_traits.phpt new file mode 100644 index 0000000000000..fb56f6ddf39e2 --- /dev/null +++ b/ext/zend_test/tests/internal_class_multiple_traits.phpt @@ -0,0 +1,47 @@ +--TEST-- +Test internal class using multiple traits via zend_class_use_internal_traits +--EXTENSIONS-- +zend_test +--FILE-- +traitProp); + +// Methods from both traits +var_dump($obj->traitMethod()); +var_dump($obj->traitMethod2()); + +// Static property from trait 2 +var_dump(_ZendTestClassWithMultipleTraits::$staticTraitProp); + +// Reflection should show both traits +$rc = new ReflectionClass(_ZendTestClassWithMultipleTraits::class); +$traits = $rc->getTraitNames(); +sort($traits); +var_dump(count($traits)); +var_dump($traits); + +echo "Done\n"; +?> +--EXPECT-- +int(123) +int(321) +int(456) +int(789) +int(101) +int(999) +int(2) +array(2) { + [0]=> + string(30) "_ZendTestTraitForInternalClass" + [1]=> + string(31) "_ZendTestTraitForInternalClass2" +} +Done diff --git a/ext/zend_test/tests/internal_class_trait.phpt b/ext/zend_test/tests/internal_class_trait.phpt new file mode 100644 index 0000000000000..471b4d2a5a7af --- /dev/null +++ b/ext/zend_test/tests/internal_class_trait.phpt @@ -0,0 +1,31 @@ +--TEST-- +Test internal class using trait via zend_class_use_internal_traits +--EXTENSIONS-- +zend_test +--FILE-- +traitProp); + +var_dump($obj->traitMethod()); + +var_dump(method_exists(_ZendTestClassWithTrait::class, 'traitMethod')); + +$rc = new ReflectionClass(_ZendTestClassWithTrait::class); +$traits = $rc->getTraitNames(); +var_dump(count($traits)); +var_dump(in_array('_ZendTestTraitForInternalClass', $traits)); + +echo "Done\n"; +?> +--EXPECT-- +int(123) +int(456) +int(789) +bool(true) +int(1) +bool(true) +Done diff --git a/ext/zend_test/tests/internal_class_trait_not_trait.phpt b/ext/zend_test/tests/internal_class_trait_not_trait.phpt new file mode 100644 index 0000000000000..c5350bd499988 --- /dev/null +++ b/ext/zend_test/tests/internal_class_trait_not_trait.phpt @@ -0,0 +1,13 @@ +--TEST-- +zend_class_use_internal_traits with non-trait class produces E_COMPILE_ERROR +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECTF-- +Fatal error: Class %s cannot use %s - it is not a trait in %s on line %d diff --git a/ext/zend_test/tests/internal_class_trait_static_prop.phpt b/ext/zend_test/tests/internal_class_trait_static_prop.phpt new file mode 100644 index 0000000000000..5389659d8ebfb --- /dev/null +++ b/ext/zend_test/tests/internal_class_trait_static_prop.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test internal class using trait with static property via zend_class_use_internal_traits +--EXTENSIONS-- +zend_test +--FILE-- +getProperty('staticTraitProp'); +var_dump($prop->isStatic()); + +echo "Done\n"; +?> +--EXPECT-- +int(999) +int(555) +bool(true) +Done diff --git a/ext/zend_test/tests/internal_class_trait_union_type.phpt b/ext/zend_test/tests/internal_class_trait_union_type.phpt new file mode 100644 index 0000000000000..ba9857e6e7413 --- /dev/null +++ b/ext/zend_test/tests/internal_class_trait_union_type.phpt @@ -0,0 +1,42 @@ +--TEST-- +Test internal class using trait with union typed property via zend_class_use_internal_traits +--EXTENSIONS-- +zend_test +--FILE-- +unionProp); + +// Assign int +$obj->unionProp = 100; +var_dump($obj->unionProp); + +// Assign string +$obj->unionProp = "hello"; +var_dump($obj->unionProp); + +// Type error +try { + $obj->unionProp = []; +} catch (TypeError $e) { + echo $e->getMessage() . "\n"; +} + +// Reflection type check +$rc = new ReflectionClass(_ZendTestClassWithUnionTypeTrait::class); +$prop = $rc->getProperty('unionProp'); +$type = $prop->getType(); +var_dump($type instanceof ReflectionUnionType); + +echo "Done\n"; +?> +--EXPECTF-- +int(42) +int(100) +string(5) "hello" +Cannot assign array to property _ZendTestClassWithUnionTypeTrait::$unionProp of type string|int +bool(true) +Done diff --git a/ext/zend_test/tests/internal_class_trait_zero_traits.phpt b/ext/zend_test/tests/internal_class_trait_zero_traits.phpt new file mode 100644 index 0000000000000..d44d7a446e225 --- /dev/null +++ b/ext/zend_test/tests/internal_class_trait_zero_traits.phpt @@ -0,0 +1,19 @@ +--TEST-- +zend_class_use_internal_traits with num_traits=0 (no-op behavior) +--EXTENSIONS-- +zend_test +--FILE-- +getTraitNames())); + +echo "Done\n"; +?> +--EXPECT-- +int(0) +Done