Skip to content

Commit 8ad32d0

Browse files
committed
Implement structs
1 parent 787f26c commit 8ad32d0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+2255
-100
lines changed

Zend/tests/readonly_classes/readonly_enum.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ readonly enum Foo
99

1010
?>
1111
--EXPECTF--
12-
Parse error: syntax error, unexpected token "enum", expecting "abstract" or "final" or "readonly" or "class" in %s on line %d
12+
Parse error: syntax error, unexpected token "enum" in %s on line %d

Zend/tests/readonly_classes/readonly_interface.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ readonly interface Foo
99

1010
?>
1111
--EXPECTF--
12-
Parse error: syntax error, unexpected token "interface", expecting "abstract" or "final" or "readonly" or "class" in %s on line %d
12+
Parse error: syntax error, unexpected token "interface" in %s on line %d

Zend/tests/readonly_classes/readonly_trait.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ readonly trait Foo
99

1010
?>
1111
--EXPECTF--
12-
Parse error: syntax error, unexpected token "trait", expecting "abstract" or "final" or "readonly" or "class" in %s on line %d
12+
Parse error: syntax error, unexpected token "trait" in %s on line %d

Zend/tests/structs/abstract.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Structs must not be marked as abstract
3+
--FILE--
4+
<?php
5+
6+
abstract struct Box {}
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Cannot use the abstract modifier on a struct, as structs are implicitly final in %s on line %d

Zend/tests/structs/array_access.phpt

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
--TEST--
2+
Structs implementing ArrayAccess
3+
--FILE--
4+
<?php
5+
6+
abstract class VectorBase implements ArrayAccess {
7+
public $elements;
8+
9+
public function offsetExists(mixed $offset): bool {
10+
return array_key_exists($offset, $this->elements);
11+
}
12+
13+
public function offsetSet(mixed $offset, mixed $value): void {
14+
if ($offset) {
15+
$this->elements[$offset] = $value;
16+
} else {
17+
$this->elements[] = $value;
18+
}
19+
}
20+
21+
public function offsetUnset(mixed $offset): void {
22+
unset($this->elements[$offset]);
23+
}
24+
}
25+
26+
struct VectorByVal extends VectorBase {
27+
public function offsetGet(mixed $offset): mixed {
28+
return $this->elements[$offset];
29+
}
30+
}
31+
32+
struct VectorByRef extends VectorBase {
33+
public function &offsetGet(mixed $offset): mixed {
34+
return $this->elements[$offset];
35+
}
36+
}
37+
38+
struct Box {
39+
public function __construct(
40+
public int $value,
41+
) {}
42+
43+
public mutating function inc() {
44+
$this->value++;
45+
}
46+
}
47+
48+
$box = new Box(1);
49+
50+
$vec = new VectorByVal();
51+
$vec[] = $box;
52+
$vec[0]->value = 2;
53+
var_dump($vec);
54+
$vec[0]->inc!();
55+
var_dump($vec);
56+
57+
$vec = new VectorByRef();
58+
$vec[] = $box;
59+
$vec[0]->value = 2;
60+
var_dump($vec);
61+
$vec[0]->inc!();
62+
var_dump($vec);
63+
64+
var_dump($box);
65+
66+
?>
67+
--EXPECT--
68+
object(VectorByVal)#2 (1) {
69+
["elements"]=>
70+
array(1) {
71+
[0]=>
72+
object(Box)#1 (1) {
73+
["value"]=>
74+
int(1)
75+
}
76+
}
77+
}
78+
object(VectorByVal)#2 (1) {
79+
["elements"]=>
80+
array(1) {
81+
[0]=>
82+
object(Box)#1 (1) {
83+
["value"]=>
84+
int(1)
85+
}
86+
}
87+
}
88+
object(VectorByRef)#3 (1) {
89+
["elements"]=>
90+
array(1) {
91+
[0]=>
92+
object(Box)#2 (1) {
93+
["value"]=>
94+
int(2)
95+
}
96+
}
97+
}
98+
object(VectorByRef)#3 (1) {
99+
["elements"]=>
100+
array(1) {
101+
[0]=>
102+
object(Box)#2 (1) {
103+
["value"]=>
104+
int(3)
105+
}
106+
}
107+
}
108+
object(Box)#1 (1) {
109+
["value"]=>
110+
int(1)
111+
}

Zend/tests/structs/assign_op.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Assign op on structs
3+
--FILE--
4+
<?php
5+
6+
struct Box {
7+
public function __construct(
8+
public $value,
9+
) {}
10+
}
11+
12+
$a = new Box(0);
13+
$b = $a;
14+
$b->value += 1;
15+
var_dump($a);
16+
var_dump($b);
17+
18+
?>
19+
--EXPECT--
20+
object(Box)#1 (1) {
21+
["value"]=>
22+
int(0)
23+
}
24+
object(Box)#2 (1) {
25+
["value"]=>
26+
int(1)
27+
}

Zend/tests/structs/assign_ref.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Assign ref on structs
3+
--FILE--
4+
<?php
5+
6+
struct Box {
7+
public $value;
8+
}
9+
10+
$a = new Box();
11+
$a->value = 1;
12+
$b = $a;
13+
$c = 2;
14+
$b->value = &$c;
15+
var_dump($a);
16+
var_dump($b);
17+
18+
?>
19+
--EXPECT--
20+
object(Box)#1 (1) {
21+
["value"]=>
22+
int(1)
23+
}
24+
object(Box)#2 (1) {
25+
["value"]=>
26+
&int(2)
27+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Send structs
3+
--FILE--
4+
<?php
5+
6+
struct Box {
7+
public function __construct(
8+
public $value,
9+
) {}
10+
}
11+
12+
$a = new Box(42);
13+
$a->value = $a;
14+
var_dump($a);
15+
16+
$b = new Box(42);
17+
$b->value = &$b;
18+
var_dump($b);
19+
20+
?>
21+
--EXPECT--
22+
object(Box)#2 (1) {
23+
["value"]=>
24+
object(Box)#1 (1) {
25+
["value"]=>
26+
int(42)
27+
}
28+
}
29+
object(Box)#3 (1) {
30+
["value"]=>
31+
*RECURSION*
32+
}

Zend/tests/structs/basic.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Basic structs
3+
--FILE--
4+
<?php
5+
6+
struct Point {
7+
public function __construct(
8+
public int $x,
9+
public int $y,
10+
) {}
11+
}
12+
13+
$a = new Point(1, 1);
14+
$b = $a;
15+
$b->x = 2;
16+
$b->y = 2;
17+
var_dump($a);
18+
var_dump($b);
19+
20+
?>
21+
--EXPECT--
22+
object(Point)#1 (2) {
23+
["x"]=>
24+
int(1)
25+
["y"]=>
26+
int(1)
27+
}
28+
object(Point)#2 (2) {
29+
["x"]=>
30+
int(2)
31+
["y"]=>
32+
int(2)
33+
}

Zend/tests/structs/final.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Structs must not be marked as final
3+
--FILE--
4+
<?php
5+
6+
final struct Box {}
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Cannot use the final modifier on a struct, as structs are implicitly final in %s on line %d
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Basic structs
3+
--FILE--
4+
<?php
5+
6+
struct Child {
7+
public function __construct(
8+
public $value,
9+
) {}
10+
}
11+
12+
class Parent_ {
13+
public function __construct(
14+
public Child $writableChild,
15+
public readonly Child $readonlyChild,
16+
) {}
17+
}
18+
19+
$parent = new Parent_(new Child(1), new Child(1));
20+
$parent->writableChild->value = 2;
21+
try {
22+
$parent->readonlyChild->value = 2;
23+
} catch (Error $e) {
24+
echo $e->getMessage(), "\n";
25+
}
26+
27+
var_dump($parent);
28+
29+
?>
30+
--EXPECTF--
31+
Cannot indirectly modify readonly property Parent_::$readonlyChild
32+
object(Parent_)#1 (2) {
33+
["writableChild"]=>
34+
object(Child)#%d (1) {
35+
["value"]=>
36+
int(2)
37+
}
38+
["readonlyChild"]=>
39+
object(Child)#%d (1) {
40+
["value"]=>
41+
int(1)
42+
}
43+
}

Zend/tests/structs/is_identical.phpt

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
--TEST--
2+
=== on structs
3+
--FILE--
4+
<?php
5+
6+
struct Box {
7+
public function __construct(
8+
public $value,
9+
) {}
10+
}
11+
12+
$a = new Box(1);
13+
$b = new Box(2);
14+
$c = $a;
15+
$d = $a;
16+
$d->value++;
17+
$e = new Box('1');
18+
19+
$values = [$a, $b, $c, $d, $e];
20+
foreach ($values as $l) {
21+
foreach ($values as $r) {
22+
echo var_export($l->value, true)
23+
. ' === '
24+
. var_export($r->value, true)
25+
. ' => '
26+
. ($l === $r ? 'true' : 'false')
27+
. "\n";
28+
}
29+
}
30+
31+
#[\AllowDynamicProperties]
32+
struct Point {}
33+
34+
$a = new Point();
35+
$a->x = 1;
36+
$a->y = 1;
37+
$b = new Point();
38+
$b->y = 1;
39+
$b->x = 1;
40+
var_dump($a === $b);
41+
unset($b->y);
42+
$b->y = 1;
43+
var_dump($a === $b);
44+
45+
?>
46+
--EXPECT--
47+
1 === 1 => true
48+
1 === 2 => false
49+
1 === 1 => true
50+
1 === 2 => false
51+
1 === '1' => false
52+
2 === 1 => false
53+
2 === 2 => true
54+
2 === 1 => false
55+
2 === 2 => true
56+
2 === '1' => false
57+
1 === 1 => true
58+
1 === 2 => false
59+
1 === 1 => true
60+
1 === 2 => false
61+
1 === '1' => false
62+
2 === 1 => false
63+
2 === 2 => true
64+
2 === 1 => false
65+
2 === 2 => true
66+
2 === '1' => false
67+
'1' === 1 => false
68+
'1' === 2 => false
69+
'1' === 1 => false
70+
'1' === 2 => false
71+
'1' === '1' => true
72+
bool(false)
73+
bool(true)

0 commit comments

Comments
 (0)