Skip to content

Commit 1aa6fe5

Browse files
committed
Some review fixes
1 parent dcf1ac3 commit 1aa6fe5

File tree

4 files changed

+44
-69
lines changed

4 files changed

+44
-69
lines changed
Lines changed: 28 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,46 @@
11
--TEST--
2-
Test that __clone() can write to readonly properties
2+
Test that __clone() unset and reassign properties
33
--FILE--
44
<?php
55

6-
class Counter
7-
{
8-
private static int $counter = 0;
9-
10-
public readonly int $count;
11-
private readonly int $foo;
12-
13-
public function __construct()
14-
{
15-
$this->count = ++self::$counter;
16-
$this->foo = 0;
17-
}
18-
19-
public function count(?int $count = null): static
20-
{
21-
$new = clone $this;
22-
$new->count = $count ?? ++self::$counter;
23-
24-
return $new;
25-
}
6+
class Foo {
7+
public function __construct(
8+
public readonly stdClass $bar,
9+
) {}
2610

2711
public function __clone()
2812
{
29-
if (is_a(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['class'] ?? '', self::class, true)) {
30-
unset($this->count);
31-
} else {
32-
$this->count = ++self::$counter;
33-
}
34-
$this->foo = 1;
13+
unset($this->bar);
14+
var_dump($this);
15+
$this->bar = new stdClass();
3516
}
3617
}
3718

38-
$a = new Counter();
39-
var_dump($a);
40-
41-
var_dump(clone $a);
42-
43-
$b = $a->count();
44-
var_dump($b);
19+
$foo = new Foo(new stdClass());
20+
var_dump($foo);
21+
$foo2 = clone $foo;
4522

46-
$c = $a->count(123);
47-
var_dump($c);
23+
var_dump($foo);
24+
var_dump($foo2);
4825

4926
?>
5027
--EXPECTF--
51-
object(Counter)#%d (2) {
52-
["count"]=>
53-
int(1)
54-
["foo":"Counter":private]=>
55-
int(0)
28+
object(Foo)#1 (%d) {
29+
["bar"]=>
30+
object(stdClass)#2 (%d) {
31+
}
5632
}
57-
object(Counter)#%d (2) {
58-
["count"]=>
59-
int(2)
60-
["foo":"Counter":private]=>
61-
int(1)
33+
object(Foo)#3 (%d) {
34+
["bar"]=>
35+
uninitialized(stdClass)
6236
}
63-
object(Counter)#%d (2) {
64-
["count"]=>
65-
int(3)
66-
["foo":"Counter":private]=>
67-
int(1)
37+
object(Foo)#1 (%d) {
38+
["bar"]=>
39+
object(stdClass)#2 (%d) {
40+
}
6841
}
69-
object(Counter)#%d (2) {
70-
["count"]=>
71-
int(123)
72-
["foo":"Counter":private]=>
73-
int(1)
42+
object(Foo)#3 (%d) {
43+
["bar"]=>
44+
object(stdClass)#4 (%d) {
45+
}
7446
}
Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,37 @@
11
--TEST--
2-
Test that __clone() unset properties
2+
__clone() can indirectly modify unlocked readonly properties
33
--FILE--
44
<?php
55

66
class Foo {
77
public function __construct(
8-
public readonly stdClass $bar,
8+
public readonly array $bar
99
) {}
1010

1111
public function __clone()
1212
{
13-
unset($this->bar);
13+
$this->bar['bar'] = 'bar';
1414
}
1515
}
1616

17-
$foo = new Foo(new stdClass());
18-
$foo2 = clone $foo;
19-
20-
var_dump($foo);
21-
var_dump($foo2);
17+
$foo = new Foo([]);
18+
// First call fills the cache slot
19+
var_dump(clone $foo);
20+
var_dump(clone $foo);
2221

2322
?>
2423
--EXPECTF--
25-
object(Foo)#1 (%d) {
24+
object(Foo)#2 (%d) {
2625
["bar"]=>
27-
object(stdClass)#2 (%d) {
26+
array(1) {
27+
["bar"]=>
28+
string(3) "bar"
2829
}
2930
}
30-
object(Foo)#3 (%d) {
31+
object(Foo)#2 (%d) {
3132
["bar"]=>
32-
uninitialized(stdClass)
33+
array(1) {
34+
["bar"]=>
35+
string(3) "bar"
36+
}
3337
}

Zend/zend_execute.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3167,7 +3167,6 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c
31673167
ZVAL_COPY(result, ptr);
31683168
} else if (Z_PROP_FLAG_P(ptr) & IS_PROP_REINITABLE) {
31693169
Z_PROP_FLAG_P(ptr) &= ~IS_PROP_REINITABLE;
3170-
ZVAL_COPY(result, ptr);
31713170
} else {
31723171
zend_readonly_property_modification_error(prop_info);
31733172
ZVAL_ERROR(result);

0 commit comments

Comments
 (0)