Skip to content

Commit 0d7cde8

Browse files
committed
compare by value
1 parent c84b7ed commit 0d7cde8

19 files changed

+169
-5
lines changed

Zend/tests/data_class_001.phpt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
Data classes can be defined and compared.
3+
--FILE--
4+
<?php
5+
6+
data class Point {
7+
public function __construct(public int $x, public int $y) {}
8+
}
9+
10+
$p1 = new Point(1, 2);
11+
$p2 = new Point(1, 2);
12+
$p3 = new Point(2, 3);
13+
14+
var_dump($p1 === $p2);
15+
var_dump($p1 !== $p2);
16+
var_dump($p1 === $p3);
17+
var_dump($p1 !== $p3);
18+
var_dump($p1);
19+
?>
20+
--EXPECT--
21+
bool(true)
22+
bool(false)
23+
bool(false)
24+
bool(true)
25+
data object(Point)#1 (2) {
26+
["x"]=>
27+
int(1)
28+
["y"]=>
29+
int(2)
30+
}

Zend/tests/data_class_002.phpt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
Data classes can be combined with inheritance and other features.
3+
--FILE--
4+
<?php
5+
6+
data class Point {
7+
public function __construct(public int $x, public int $y) {}
8+
}
9+
10+
final data class Point3D extends Point {
11+
public function __construct(int $x, int $y, public int $z) {
12+
parent::__construct($x, $y);
13+
}
14+
}
15+
16+
$p2 = new Point3D(1, 2, 3);
17+
$p3 = new Point3D(1, 2, 3);
18+
$p4 = new Point3D(2, 3, 4);
19+
20+
var_dump($p2 === $p3);
21+
var_dump($p2 !== $p3);
22+
var_dump($p2 === $p4);
23+
var_dump($p2 !== $p4);
24+
?>
25+
--EXPECT--
26+
bool(true)
27+
bool(false)
28+
bool(false)
29+
bool(true)

Zend/tests/data_class_003.phpt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Data class inheritance rules are enforced.
3+
--FILE--
4+
<?php
5+
6+
class Point {
7+
public function __construct(public int $x, public int $y) {}
8+
}
9+
10+
data class Point3D extends Point {
11+
public function __construct(int $x, int $y, public int $z) {
12+
parent::__construct($x, $y);
13+
}
14+
}
15+
?>
16+
--EXPECTF--
17+
Fatal error: Data class Point3D cannot extend non-data class Point in %s on line %d

Zend/tests/data_class_004.phpt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Reflection should work
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public function bar() {}
8+
}
9+
10+
data class Bar {
11+
public function baz() {}
12+
}
13+
14+
$foo = new ReflectionClass(Foo::class);
15+
$bar = new ReflectionClass(Bar::class);
16+
var_dump($foo->isDataClass());
17+
var_dump($bar->isDataClass());
18+
?>
19+
--EXPECT--
20+
bool(false)
21+
bool(true)

Zend/zend_ast.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,9 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
18981898
if (decl->flags & ZEND_ACC_READONLY_CLASS) {
18991899
smart_str_appends(str, "readonly ");
19001900
}
1901+
if (decl->flags & ZEND_ACC_DATA_CLASS) {
1902+
smart_str_appends(str, "data ");
1903+
}
19011904
smart_str_appends(str, "class ");
19021905
}
19031906
smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));

Zend/zend_attributes.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ static void validate_allow_dynamic_properties(
8686
ZSTR_VAL(scope->name)
8787
);
8888
}
89+
if (scope->ce_flags & ZEND_ACC_DATA_CLASS) {
90+
zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to data class %s",
91+
ZSTR_VAL(scope->name)
92+
);
93+
}
8994
if (scope->ce_flags & ZEND_ACC_ENUM) {
9095
zend_error_noreturn(E_ERROR, "Cannot apply #[AllowDynamicProperties] to enum %s",
9196
ZSTR_VAL(scope->name)

Zend/zend_compile.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,6 +862,8 @@ static const char *zend_modifier_token_to_string(uint32_t token)
862862
return "final";
863863
case T_READONLY:
864864
return "readonly";
865+
case T_DATA:
866+
return "data";
865867
case T_ABSTRACT:
866868
return "abstract";
867869
case T_PUBLIC_SET:
@@ -995,6 +997,10 @@ uint32_t zend_add_class_modifier(uint32_t flags, uint32_t new_flag) /* {{{ */
995997
zend_throw_exception(zend_ce_compile_error, "Multiple readonly modifiers are not allowed", 0);
996998
return 0;
997999
}
1000+
if ((flags & ZEND_ACC_DATA_CLASS) && (new_flag & ZEND_ACC_DATA_CLASS)) {
1001+
zend_throw_exception(zend_ce_compile_error, "Multiple data modifiers are not allowed", 0);
1002+
return 0;
1003+
}
9981004
if ((new_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) && (new_flags & ZEND_ACC_FINAL)) {
9991005
zend_throw_exception(zend_ce_compile_error,
10001006
"Cannot use the final modifier on an abstract class", 0);
@@ -1020,6 +1026,10 @@ uint32_t zend_add_anonymous_class_modifier(uint32_t flags, uint32_t new_flag)
10201026
zend_throw_exception(zend_ce_compile_error, "Multiple readonly modifiers are not allowed", 0);
10211027
return 0;
10221028
}
1029+
if ((flags & ZEND_ACC_DATA_CLASS) && (new_flag & ZEND_ACC_DATA_CLASS)) {
1030+
zend_throw_exception(zend_ce_compile_error, "Multiple data modifiers are not allowed", 0);
1031+
return 0;
1032+
}
10231033
return new_flags;
10241034
}
10251035

Zend/zend_compile.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ typedef struct _zend_oparray_context {
267267
#define ZEND_ACC_PROTECTED_SET (1 << 11) /* | | X | */
268268
#define ZEND_ACC_PRIVATE_SET (1 << 12) /* | | X | */
269269
/* | | | */
270-
/* Class Flags (unused: 30,31) | | | */
270+
/* Class Flags (unused: 31) | | | */
271271
/* =========== | | | */
272272
/* | | | */
273273
/* Special class types | | | */
@@ -333,6 +333,9 @@ typedef struct _zend_oparray_context {
333333
/* Class cannot be serialized or unserialized | | | */
334334
#define ZEND_ACC_NOT_SERIALIZABLE (1 << 29) /* X | | | */
335335
/* | | | */
336+
/* Class is compared by value | | | */
337+
#define ZEND_ACC_DATA_CLASS (1 << 30) /* X | | | */
338+
/* | | | */
336339
/* Function Flags (unused: 29-30) | | | */
337340
/* ============== | | | */
338341
/* | | | */

Zend/zend_inheritance.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1783,6 +1783,13 @@ ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *par
17831783
);
17841784
}
17851785

1786+
if (UNEXPECTED((ce->ce_flags & ZEND_ACC_DATA_CLASS) != (parent_ce->ce_flags & ZEND_ACC_DATA_CLASS))) {
1787+
zend_error_noreturn(E_COMPILE_ERROR, "%s class %s cannot extend %s class %s",
1788+
ce->ce_flags & ZEND_ACC_DATA_CLASS ? "Data" : "Non-data", ZSTR_VAL(ce->name),
1789+
parent_ce->ce_flags & ZEND_ACC_DATA_CLASS ? "data" : "non-data", ZSTR_VAL(parent_ce->name)
1790+
);
1791+
}
1792+
17861793
if (ce->parent_name) {
17871794
zend_string_release_ex(ce->parent_name, 0);
17881795
}

Zend/zend_language_parser.y

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
158158
%token <ident> T_PROTECTED_SET "'protected(set)'"
159159
%token <ident> T_PUBLIC_SET "'public(set)'"
160160
%token <ident> T_READONLY "'readonly'"
161+
%token <ident> T_DATA "'data'"
161162
%token <ident> T_VAR "'var'"
162163
%token <ident> T_UNSET "'unset'"
163164
%token <ident> T_ISSET "'isset'"
@@ -314,7 +315,7 @@ reserved_non_modifiers:
314315

315316
semi_reserved:
316317
reserved_non_modifiers
317-
| T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC | T_READONLY
318+
| T_STATIC | T_ABSTRACT | T_FINAL | T_PRIVATE | T_PROTECTED | T_PUBLIC | T_READONLY | T_DATA
318319
;
319320

320321
ampersand:
@@ -624,6 +625,7 @@ class_modifier:
624625
T_ABSTRACT { $$ = ZEND_ACC_EXPLICIT_ABSTRACT_CLASS; }
625626
| T_FINAL { $$ = ZEND_ACC_FINAL; }
626627
| T_READONLY { $$ = ZEND_ACC_READONLY_CLASS|ZEND_ACC_NO_DYNAMIC_PROPERTIES; }
628+
| T_DATA { $$ = ZEND_ACC_DATA_CLASS; }
627629
;
628630

629631
trait_declaration_statement:

0 commit comments

Comments
 (0)