summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/tests/type_declarations/mixed/casting/mixed_cast_error.phpt10
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error1.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error2.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error3.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error4.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success1.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success2.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success3.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success4.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success5.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success6.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success7.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error1.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error2.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error3.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error4.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error5.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error6.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error7.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error8.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_success.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error1.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error2.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error3.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success1.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success2.phpt57
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success3.phpt27
-rw-r--r--Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success4.phpt17
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_class_error.phpt12
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error1.phpt12
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error2.phpt12
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_parameter_success.phpt11
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_parameter_sucess4.phpt11
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_return_error.phpt13
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_return_success.phpt12
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/mixed_void_return_error.phpt13
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/nullable_mixed_parameter_error.phpt12
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/nullable_mixed_property_error.phpt13
-rw-r--r--Zend/tests/type_declarations/mixed/syntax/nullable_mixed_return_error.phpt12
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_parameter_strict_success.phpt20
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_parameter_weak_success.phpt19
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_property_strict_success.phpt36
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_property_weak_success.phpt35
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_return_strict_error.phpt20
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_return_strict_success.phpt20
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_return_weak_error.phpt18
-rw-r--r--Zend/tests/type_declarations/mixed/validation/mixed_return_weak_success.phpt19
-rw-r--r--Zend/zend_API.c2
-rw-r--r--Zend/zend_ast.c1
-rw-r--r--Zend/zend_compile.c35
-rw-r--r--Zend/zend_inheritance.c4
-rw-r--r--Zend/zend_string.h1
-rw-r--r--Zend/zend_types.h7
-rw-r--r--ext/reflection/php_reflection.c6
-rw-r--r--ext/reflection/tests/mixed_type.phpt32
55 files changed, 927 insertions, 15 deletions
diff --git a/Zend/tests/type_declarations/mixed/casting/mixed_cast_error.phpt b/Zend/tests/type_declarations/mixed/casting/mixed_cast_error.phpt
new file mode 100644
index 0000000000..416bddddc2
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/casting/mixed_cast_error.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Test that a mixed casting is not supported
+--FILE--
+<?php
+
+$foo = (mixed) 12;
+
+?>
+--EXPECTF--
+Parse error: syntax error, unexpected '12' (T_LNUMBER) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error1.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error1.phpt
new file mode 100644
index 0000000000..88e4a3da50
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error1.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a mixed parameter type can't be overridden by a built-in type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(mixed $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(bool $a) {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of Bar::method(bool $a) must be compatible with Foo::method(mixed $a) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error2.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error2.phpt
new file mode 100644
index 0000000000..e0a4975f86
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error2.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a mixed parameter type can't be overridden by a nullable built-in type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(mixed $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(?int $a) {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of Bar::method(?int $a) must be compatible with Foo::method(mixed $a) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error3.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error3.phpt
new file mode 100644
index 0000000000..705813d30d
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error3.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a mixed parameter type can't be overridden by a union of all built-in types
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(mixed $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(bool|int|float|string|array|object|null $a) {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of Bar::method(object|array|string|int|float|bool|null $a) must be compatible with Foo::method(mixed $a) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error4.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error4.phpt
new file mode 100644
index 0000000000..5bffe6495e
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_error4.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a mixed parameter type can't be overridden by a union type of classes
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(mixed $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(stdClass|Foo $a) {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of Bar::method(stdClass|Foo $a) must be compatible with Foo::method(mixed $a) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success1.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success1.phpt
new file mode 100644
index 0000000000..7b3403c6de
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success1.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a mixed parameter type supports invariance
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(mixed $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(mixed $a) {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success2.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success2.phpt
new file mode 100644
index 0000000000..9bbd78a427
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success2.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a mixed parameter type can be overridden by no type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(mixed $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method($a) {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success3.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success3.phpt
new file mode 100644
index 0000000000..bc3be65688
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success3.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a parameter of no type can be overridden by the mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method($a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(mixed $a) {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success4.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success4.phpt
new file mode 100644
index 0000000000..365ea6aeb7
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success4.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a parameter of a built-in type can be overridden by the mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(int $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(mixed $a) {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success5.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success5.phpt
new file mode 100644
index 0000000000..9cd40776c5
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success5.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a parameter of a nullable built-in type can be overridden by the mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(?int $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(mixed $a) {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success6.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success6.phpt
new file mode 100644
index 0000000000..0621d5a872
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success6.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a parameter of a union of all built-in types can be overridden by the mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(bool|int|float|string|array|object|null $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(mixed $a) {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success7.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success7.phpt
new file mode 100644
index 0000000000..e5efc82072
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_parameter_inheritance_success7.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a parameter of a union type of classes can be overridden by the mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(stdClass|Foo $a) {}
+}
+
+class Bar extends Foo
+{
+ public function method(mixed $a) {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error1.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error1.phpt
new file mode 100644
index 0000000000..b1fba7a716
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error1.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a property of mixed type can't be overridden by a property of a built-in type
+--FILE--
+<?php
+
+class Foo
+{
+ public mixed $property1;
+}
+
+class Bar extends Foo
+{
+ public int $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must be mixed (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error2.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error2.phpt
new file mode 100644
index 0000000000..8052dfcec1
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error2.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a property of mixed type can't be overridden by a property of class type
+--FILE--
+<?php
+
+class Foo
+{
+ public mixed $property1;
+}
+
+class Bar extends Foo
+{
+ public stdClass $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must be mixed (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error3.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error3.phpt
new file mode 100644
index 0000000000..4199bcd3a2
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error3.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a property of mixed type can't be overridden by an untyped property
+--FILE--
+<?php
+
+class Foo
+{
+ public mixed $property1;
+}
+
+class Bar extends Foo
+{
+ public $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must be mixed (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error4.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error4.phpt
new file mode 100644
index 0000000000..bc79d757ee
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error4.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a property of mixed type can't be overridden by a property of a union type
+--FILE--
+<?php
+
+class Foo
+{
+ public mixed $property1;
+}
+
+class Bar extends Foo
+{
+ public bool|int|float|string|array|object|null $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must be mixed (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error5.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error5.phpt
new file mode 100644
index 0000000000..8f2c6dc9be
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error5.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a property of a built-in type can't be overridden by a property of mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public int $property1;
+}
+
+class Bar extends Foo
+{
+ public mixed $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must be int (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error6.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error6.phpt
new file mode 100644
index 0000000000..2ba936c119
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error6.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a property of class type can't be overridden by a property of mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public stdClass $property1;
+}
+
+class Bar extends Foo
+{
+ public mixed $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must be stdClass (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error7.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error7.phpt
new file mode 100644
index 0000000000..138952b3df
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error7.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that an untyped property can't be overridden by a property of mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public $property1;
+}
+
+class Bar extends Foo
+{
+ public mixed $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must not be defined (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error8.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error8.phpt
new file mode 100644
index 0000000000..6e564fa4ae
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_error8.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a property of a union type can't be overridden by a property of mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public bool|int|float|string|array|object|null $property1;
+}
+
+class Bar extends Foo
+{
+ public mixed $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type of Bar::$property1 must be object|array|string|int|float|bool|null (as in class Foo) in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_success.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_success.phpt
new file mode 100644
index 0000000000..9f4f4fa546
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_property_inheritance_success.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a property of mixed property type can be overridden by a property of mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public mixed $property1;
+}
+
+class Bar extends Foo
+{
+ public mixed $property1;
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error1.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error1.phpt
new file mode 100644
index 0000000000..f0cdf26b2d
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error1.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a mixed return type can't be overridden by the void type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(): mixed {}
+}
+
+class Bar extends Foo
+{
+ public function method(): void {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of Bar::method(): void must be compatible with Foo::method(): mixed in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error2.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error2.phpt
new file mode 100644
index 0000000000..1bca4f481a
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error2.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that a mixed return type can't be overridden by no return type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(): mixed {}
+}
+
+class Bar extends Foo
+{
+ public function method() {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of Bar::method() must be compatible with Foo::method(): mixed in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error3.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error3.phpt
new file mode 100644
index 0000000000..a16249ec0b
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_error3.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that the void return type can't be overridden by the mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(): void {}
+}
+
+class Bar extends Foo
+{
+ public function method(): mixed {}
+}
+
+?>
+--EXPECTF--
+Fatal error: Declaration of Bar::method(): mixed must be compatible with Foo::method(): void in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success1.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success1.phpt
new file mode 100644
index 0000000000..3b46f4c20f
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success1.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a mixed return value supports invariance
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(): mixed {}
+}
+
+class Bar extends Foo
+{
+ public function method(): mixed {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success2.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success2.phpt
new file mode 100644
index 0000000000..6d0f7efcfd
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success2.phpt
@@ -0,0 +1,57 @@
+--TEST--
+Test that a mixed return type can be overridden by any single (and nullable) type except void
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(): mixed {}
+}
+
+class Bar1 extends Foo
+{
+ public function method(): bool {}
+}
+
+class Bar2 extends Foo
+{
+ public function method(): int {}
+}
+
+class Bar3 extends Foo
+{
+ public function method(): float {}
+}
+
+class Bar4 extends Foo
+{
+ public function method(): string {}
+}
+
+class Bar5 extends Foo
+{
+ public function method(): array {}
+}
+
+class Bar6 extends Foo
+{
+ public function method(): object {}
+}
+
+class Bar7 extends Foo
+{
+ public function method(): stdClass {}
+}
+
+class Bar8 extends Foo
+{
+ public function method(): ?int {}
+}
+
+class Bar9 extends Foo
+{
+ public function method(): ?stdClass {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success3.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success3.phpt
new file mode 100644
index 0000000000..4b11fe2ef0
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success3.phpt
@@ -0,0 +1,27 @@
+--TEST--
+Test that a mixed return type can be overridden by any union return type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method(): mixed {}
+}
+
+class Bar1 extends Foo
+{
+ public function method(): bool|int|null {}
+}
+
+class Bar3 extends Foo
+{
+ public function method(): bool|int|float|string|array|object|null {}
+}
+
+class Bar4 extends Foo
+{
+ public function method(): stdClass|Foo {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success4.phpt b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success4.phpt
new file mode 100644
index 0000000000..ce652bc1cb
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/inheritance/mixed_return_inheritance_success4.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Test that a no return type can be overridden by the mixed type
+--FILE--
+<?php
+
+class Foo
+{
+ public function method() {}
+}
+
+class Bar extends Foo
+{
+ public function method(): mixed {}
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_class_error.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_class_error.phpt
new file mode 100644
index 0000000000..8a5a385576
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_class_error.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Test that mixed is a reserved class name
+--FILE--
+<?php
+
+class mixed
+{
+}
+
+?>
+--EXPECTF--
+Fatal error: Cannot use 'mixed' as class name as it is reserved in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error1.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error1.phpt
new file mode 100644
index 0000000000..a240dc3bfc
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error1.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Test that the mixed parameter type can't be used together with any other type
+--FILE--
+<?php
+
+function foo(mixed|int|null $a)
+{
+}
+
+?>
+--EXPECTF--
+Fatal error: Type mixed can only be used as a standalone type in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error2.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error2.phpt
new file mode 100644
index 0000000000..8f1d172810
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_error2.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Test that the nullable mixed parameter type is not valid even though a null default value
+--FILE--
+<?php
+
+function foo(?mixed $a = null)
+{
+}
+
+?>
+--EXPECTF--
+Fatal error: Type mixed cannot be marked as nullable since mixed already includes null in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_success.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_success.phpt
new file mode 100644
index 0000000000..91c72686a0
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_success.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Test that mixed is a valid parameter type
+--FILE--
+<?php
+
+function foo(mixed $a)
+{
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_sucess4.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_sucess4.phpt
new file mode 100644
index 0000000000..89f8bfa543
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_parameter_sucess4.phpt
@@ -0,0 +1,11 @@
+--TEST--
+Test that the mixed parameter type can have any default value
+--FILE--
+<?php
+
+function foo(mixed $a = null, mixed $b = false, mixed $c = 1, mixed $d = 3.13, mixed $e = "", mixed $f = [])
+{
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_return_error.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_return_error.phpt
new file mode 100644
index 0000000000..7bb8e7d4bb
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_return_error.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Test that the mixed return type can't be used together with any other type
+--FILE--
+<?php
+
+function foo(): mixed|string|null
+{
+ return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type mixed can only be used as a standalone type in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_return_success.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_return_success.phpt
new file mode 100644
index 0000000000..d8b39a80d9
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_return_success.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Test that mixed is a valid return type
+--FILE--
+<?php
+
+function foo(): mixed
+{
+ return null;
+}
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/syntax/mixed_void_return_error.phpt b/Zend/tests/type_declarations/mixed/syntax/mixed_void_return_error.phpt
new file mode 100644
index 0000000000..7c66e310a5
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/mixed_void_return_error.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Test that the mixed|void return type is not valid
+--FILE--
+<?php
+
+function foo(): mixed|void
+{
+ return null;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type mixed can only be used as a standalone type in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_parameter_error.phpt b/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_parameter_error.phpt
new file mode 100644
index 0000000000..f89238ec22
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_parameter_error.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Test that the nullable mixed parameter type is not valid
+--FILE--
+<?php
+
+function foo(?mixed $a)
+{
+}
+
+?>
+--EXPECTF--
+Fatal error: Type mixed cannot be marked as nullable since mixed already includes null in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_property_error.phpt b/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_property_error.phpt
new file mode 100644
index 0000000000..f5c8dadce7
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_property_error.phpt
@@ -0,0 +1,13 @@
+--TEST--
+Test that the nullable mixed property type is not valid
+--FILE--
+<?php
+
+class Foo
+{
+ public ?mixed $property1;
+}
+
+?>
+--EXPECTF--
+Fatal error: Type mixed cannot be marked as nullable since mixed already includes null in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_return_error.phpt b/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_return_error.phpt
new file mode 100644
index 0000000000..945e7dcc8d
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/syntax/nullable_mixed_return_error.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Test that the nullable mixed return type is not valid
+--FILE--
+<?php
+
+function foo(): ?mixed
+{
+}
+
+?>
+--EXPECTF--
+Fatal error: Type mixed cannot be marked as nullable since mixed already includes null in %s on line %d
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_parameter_strict_success.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_parameter_strict_success.phpt
new file mode 100644
index 0000000000..01cb09f269
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_parameter_strict_success.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Test that the mixed parameter type accepts any kind of arguments in strict mode
+--FILE--
+<?php
+declare(strict_types=1);
+
+function foo(mixed $a)
+{
+}
+
+foo(null);
+foo(false);
+foo(1);
+foo(3.14);
+foo("");
+foo([]);
+foo(new stdClass());
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_parameter_weak_success.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_parameter_weak_success.phpt
new file mode 100644
index 0000000000..e84a41f45f
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_parameter_weak_success.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Test that the mixed parameter type accepts any kind of arguments in weak mode
+--FILE--
+<?php
+
+function foo(mixed $a)
+{
+}
+
+foo(null);
+foo(false);
+foo(1);
+foo(3.14);
+foo("");
+foo([]);
+foo(new stdClass());
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_property_strict_success.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_property_strict_success.phpt
new file mode 100644
index 0000000000..8a2c600020
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_property_strict_success.phpt
@@ -0,0 +1,36 @@
+--TEST--
+Test that the mixed property type accepts any kind of value in strict mode
+--FILE--
+<?php
+declare(strict_types=1);
+
+class Foo
+{
+ public mixed $property1;
+ public mixed $property2 = null;
+ public mixed $property3 = false;
+ public mixed $property4 = true;
+ public mixed $property5 = 1;
+ public mixed $property6 = 3.14;
+ public mixed $property7 = "foo";
+ public mixed $property8 = [];
+ public mixed $property9;
+
+ public function __construct()
+ {
+ $this->property9 = fopen(__FILE__, "r");
+ $this->property9 = new stdClass();
+ }
+}
+
+$foo = new Foo();
+
+try {
+ $foo->property1;
+} catch (Error $exception) {
+ echo $exception->getMessage() . "\n";
+}
+
+?>
+--EXPECT--
+Typed property Foo::$property1 must not be accessed before initialization
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_property_weak_success.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_property_weak_success.phpt
new file mode 100644
index 0000000000..e83023d54c
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_property_weak_success.phpt
@@ -0,0 +1,35 @@
+--TEST--
+Test that the mixed property type accepts any kind of value in weak mode
+--FILE--
+<?php
+
+class Foo
+{
+ public mixed $property1;
+ public mixed $property2 = null;
+ public mixed $property3 = false;
+ public mixed $property4 = true;
+ public mixed $property5 = 1;
+ public mixed $property6 = 3.14;
+ public mixed $property7 = "foo";
+ public mixed $property8 = [];
+ public mixed $property9;
+
+ public function __construct()
+ {
+ $this->property9 = fopen(__FILE__, "r");
+ $this->property9 = new stdClass();
+ }
+}
+
+$foo = new Foo();
+
+try {
+ $foo->property1;
+} catch (Error $exception) {
+ echo $exception->getMessage() . "\n";
+}
+
+?>
+--EXPECT--
+Typed property Foo::$property1 must not be accessed before initialization
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_return_strict_error.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_return_strict_error.phpt
new file mode 100644
index 0000000000..ded74b0467
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_return_strict_error.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Test that the mixed return type is not compatible with a void return value in strict mode
+--FILE--
+<?php
+declare(strict_types=1);
+
+function foo(): mixed
+{
+}
+
+try {
+ foo();
+} catch (TypeError $exception) {
+ echo $exception->getMessage() . "\n";
+}
+
+?>
+--EXPECTF--
+Return value of foo() must be of type mixed, none returned
+
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_return_strict_success.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_return_strict_success.phpt
new file mode 100644
index 0000000000..d9f9ae4ba9
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_return_strict_success.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Test that the mixed return type is compatible with any kind of return value in strict mode
+--FILE--
+<?php
+declare(strict_types=1);
+
+function foo($a): mixed
+{
+ return $a;
+}
+
+foo(null);
+foo(false);
+foo(1);
+foo("");
+foo([]);
+foo(new stdClass());
+
+?>
+--EXPECT--
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_return_weak_error.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_return_weak_error.phpt
new file mode 100644
index 0000000000..316f465877
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_return_weak_error.phpt
@@ -0,0 +1,18 @@
+--TEST--
+Test that the mixed return type is not compatible with a void return value
+--FILE--
+<?php
+
+function foo(): mixed
+{
+}
+
+try {
+ foo();
+} catch (TypeError $exception) {
+ echo $exception->getMessage() . "\n";
+}
+
+?>
+--EXPECT--
+Return value of foo() must be of type mixed, none returned
diff --git a/Zend/tests/type_declarations/mixed/validation/mixed_return_weak_success.phpt b/Zend/tests/type_declarations/mixed/validation/mixed_return_weak_success.phpt
new file mode 100644
index 0000000000..23f56c13e7
--- /dev/null
+++ b/Zend/tests/type_declarations/mixed/validation/mixed_return_weak_success.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Test that the mixed return type is compatible with any kind of return value in weak mode
+--FILE--
+<?php
+
+function foo($a): mixed
+{
+ return $a;
+}
+
+foo(null);
+foo(false);
+foo(1);
+foo("");
+foo([]);
+foo(new stdClass());
+
+?>
+--EXPECT--
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index cd72a6f156..d7edc4b0a5 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -123,6 +123,8 @@ ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */
return "array";
case IS_VOID:
return "void";
+ case IS_MIXED:
+ return "mixed";
case _IS_NUMBER:
return "number";
EMPTY_SWITCH_DEFAULT_CASE()
diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c
index 7cfc0450fd..2b5d1ea324 100644
--- a/Zend/zend_ast.c
+++ b/Zend/zend_ast.c
@@ -1572,6 +1572,7 @@ simple_list:
case IS_ARRAY: APPEND_STR("array");
case IS_CALLABLE: APPEND_STR("callable");
case IS_STATIC: APPEND_STR("static");
+ case IS_MIXED: APPEND_STR("mixed");
EMPTY_SWITCH_DEFAULT_CASE();
}
break;
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 9c6546ac41..9206a15be5 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -172,6 +172,7 @@ static const struct reserved_class_name reserved_class_names[] = {
{ZEND_STRL("void")},
{ZEND_STRL("iterable")},
{ZEND_STRL("object")},
+ {ZEND_STRL("mixed")},
{NULL, 0}
};
@@ -220,6 +221,7 @@ static const builtin_type_info builtin_types[] = {
{ZEND_STRL("void"), IS_VOID},
{ZEND_STRL("iterable"), IS_ITERABLE},
{ZEND_STRL("object"), IS_OBJECT},
+ {ZEND_STRL("mixed"), IS_MIXED},
{NULL, 0, IS_UNDEF}
};
@@ -1166,6 +1168,7 @@ static zend_string *resolve_class_name(zend_string *name, zend_class_entry *scop
zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scope) {
zend_string *str = NULL;
+
if (ZEND_TYPE_HAS_LIST(type)) {
zend_type *list_type;
ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(type), list_type) {
@@ -1182,6 +1185,12 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
}
uint32_t type_mask = ZEND_TYPE_FULL_MASK(type);
+
+ if (type_mask == MAY_BE_ANY) {
+ str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_MIXED));
+
+ return str;
+ }
if (type_mask & MAY_BE_STATIC) {
zend_string *name = ZSTR_KNOWN(ZEND_STR_STATIC);
if (scope) {
@@ -2296,11 +2305,14 @@ static void zend_emit_return_type_check(
}
}
- if (expr && expr->op_type == IS_CONST) {
- if (ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE(expr->u.constant))) {
- /* we don't need run-time check */
- return;
- }
+ if (expr && ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY) {
+ /* we don't need run-time check for mixed return type */
+ return;
+ }
+
+ if (expr && expr->op_type == IS_CONST && ZEND_TYPE_CONTAINS_CODE(type, Z_TYPE(expr->u.constant))) {
+ /* we don't need run-time check */
+ return;
}
opline = zend_emit_op(NULL, ZEND_VERIFY_RETURN_TYPE, expr, NULL);
@@ -5576,8 +5588,13 @@ static zend_type zend_compile_typename(
for (uint32_t i = 0; i < list->children; i++) {
zend_ast *type_ast = list->child[i];
zend_type single_type = zend_compile_single_typename(type_ast);
- uint32_t type_mask_overlap =
- ZEND_TYPE_PURE_MASK(type) & ZEND_TYPE_PURE_MASK(single_type);
+ uint32_t single_type_mask = ZEND_TYPE_PURE_MASK(single_type);
+
+ if (single_type_mask == MAY_BE_ANY) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Type mixed can only be used as a standalone type");
+ }
+
+ uint32_t type_mask_overlap = ZEND_TYPE_PURE_MASK(type) & single_type_mask;
if (type_mask_overlap) {
zend_type overlap_type = ZEND_TYPE_INIT_MASK(type_mask_overlap);
zend_string *overlap_type_str = zend_type_to_string(overlap_type);
@@ -5654,6 +5671,10 @@ static zend_type zend_compile_typename(
ZSTR_VAL(type_str));
}
+ if (type_mask == MAY_BE_ANY && (orig_ast_attr & ZEND_TYPE_NULLABLE)) {
+ zend_error_noreturn(E_COMPILE_ERROR, "Type mixed cannot be marked as nullable since mixed already includes null");
+ }
+
if ((type_mask & MAY_BE_OBJECT) && (ZEND_TYPE_HAS_CLASS(type) || (type_mask & MAY_BE_STATIC))) {
zend_string *type_str = zend_type_to_string(type);
zend_error_noreturn(E_COMPILE_ERROR,
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
index 72f4888228..f42998a8f8 100644
--- a/Zend/zend_inheritance.c
+++ b/Zend/zend_inheritance.c
@@ -507,8 +507,8 @@ static inheritance_status zend_do_perform_arg_type_hint_check(
zend_class_entry *fe_scope, zend_arg_info *fe_arg_info,
zend_class_entry *proto_scope, zend_arg_info *proto_arg_info) /* {{{ */
{
- if (!ZEND_TYPE_IS_SET(fe_arg_info->type)) {
- /* Child with no type is always compatible */
+ if (!ZEND_TYPE_IS_SET(fe_arg_info->type) || ZEND_TYPE_PURE_MASK(fe_arg_info->type) == MAY_BE_ANY) {
+ /* Child with no type or mixed type is always compatible */
return INHERITANCE_SUCCESS;
}
diff --git a/Zend/zend_string.h b/Zend/zend_string.h
index 45ef3cbb01..fa794278e5 100644
--- a/Zend/zend_string.h
+++ b/Zend/zend_string.h
@@ -522,6 +522,7 @@ EMPTY_SWITCH_DEFAULT_CASE()
_(ZEND_STR_VOID, "void") \
_(ZEND_STR_FALSE, "false") \
_(ZEND_STR_NULL_LOWERCASE, "null") \
+ _(ZEND_STR_MIXED, "mixed") \
typedef enum _zend_known_string_id {
diff --git a/Zend/zend_types.h b/Zend/zend_types.h
index 3543277b77..026177cf17 100644
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@ -257,7 +257,7 @@ typedef struct {
{ NULL, (_type_mask) }
#define ZEND_TYPE_INIT_CODE(code, allow_null, extra_flags) \
- ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? MAY_BE_BOOL : (1 << (code))) \
+ ZEND_TYPE_INIT_MASK(((code) == _IS_BOOL ? MAY_BE_BOOL : ((code) == IS_MIXED ? MAY_BE_ANY : (1 << (code)))) \
| ((allow_null) ? _ZEND_TYPE_NULLABLE_BIT : 0) | (extra_flags))
#define ZEND_TYPE_INIT_PTR(ptr, type_kind, allow_null, extra_flags) \
@@ -534,6 +534,7 @@ struct _zend_ast_ref {
#define IS_ITERABLE 13
#define IS_VOID 14
#define IS_STATIC 15
+#define IS_MIXED 16
/* internal types */
#define IS_INDIRECT 12
@@ -542,8 +543,8 @@ struct _zend_ast_ref {
#define _IS_ERROR 15
/* used for casts */
-#define _IS_BOOL 16
-#define _IS_NUMBER 17
+#define _IS_BOOL 17
+#define _IS_NUMBER 18
static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
return pz->u1.v.type;
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index 1ed057d902..9aac065e38 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -1187,13 +1187,13 @@ static void reflection_type_factory(zend_type type, zval *object, zend_bool lega
reflection_object *intern;
type_reference *reference;
zend_bool is_union = is_union_type(type);
+ zend_bool is_mixed = ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY;
- reflection_instantiate(
- is_union ? reflection_union_type_ptr : reflection_named_type_ptr, object);
+ reflection_instantiate(is_union && !is_mixed ? reflection_union_type_ptr : reflection_named_type_ptr, object);
intern = Z_REFLECTION_P(object);
reference = (type_reference*) emalloc(sizeof(type_reference));
reference->type = type;
- reference->legacy_behavior = legacy_behavior && !is_union;
+ reference->legacy_behavior = legacy_behavior && !is_union && !is_mixed;
intern->ptr = reference;
intern->ref_type = REF_TYPE_TYPE;
diff --git a/ext/reflection/tests/mixed_type.phpt b/ext/reflection/tests/mixed_type.phpt
new file mode 100644
index 0000000000..d44b91789c
--- /dev/null
+++ b/ext/reflection/tests/mixed_type.phpt
@@ -0,0 +1,32 @@
+--TEST--
+Test that the mixed type is reflectable
+--FILE--
+<?php
+class A
+{
+ public mixed $a;
+
+ public function test(mixed $a): mixed {}
+}
+
+$a = new A();
+
+$object = new ReflectionObject($a);
+$method = new ReflectionMethod($a, "test");
+
+var_dump($object->getProperty("a")->getType()->getName());
+var_dump($method->getParameters()[0]->getType()->getName());
+var_dump($method->getReturnType()->getName());
+
+var_dump((string) $object->getProperty("a")->getType());
+var_dump((string) $method->getParameters()[0]->getType());
+var_dump((string) $method->getReturnType());
+
+?>
+--EXPECT--
+string(5) "mixed"
+string(5) "mixed"
+string(5) "mixed"
+string(5) "mixed"
+string(5) "mixed"
+string(5) "mixed"