Skip to content

Commit b13347b

Browse files
authored
Fix GH-19044: Protected properties are not scoped according to their prototype (#19046)
* Fix GH-19044: Protected properties are not scoped according to their prototype * Adjust after review * Simplify to using prototype even for asymmetric visibility
1 parent 4e1d3f8 commit b13347b

File tree

11 files changed

+243
-8
lines changed

11 files changed

+243
-8
lines changed

NEWS

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ PHP NEWS
77
(psumbera)
88
. Fixed bug GH-19053 (Duplicate property slot with hooks and interface
99
property). (ilutov)
10+
. Fixed bug GH-19044 (Protected properties are not scoped according to their
11+
prototype). (Bob)
1012

1113
- Hash:
1214
. Fix crash on clone failure. (nielsdos)
@@ -49,9 +51,6 @@ PHP NEWS
4951
. Fixed bug GH-18907 (Leak when creating cycle in hook). (ilutov)
5052
. Fix OSS-Fuzz #427814456. (nielsdos)
5153
. Fix OSS-Fuzz #428983568 and #428760800. (nielsdos)
52-
. Fixed bug GH-17204 (-Wuseless-escape warnings emitted by re2c). (Peter Kokot)
53-
. Fixed bug GH-19064 (Undefined symbol 'execute_ex' on Windows ARM64).
54-
(Demon)
5554

5655
- Curl:
5756
. Fix memory leaks when returning refcounted value from curl callback.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (protected(set) on non-hooked property)
3+
--FILE--
4+
<?php
5+
6+
class P {
7+
public mixed $foo { get => 42; }
8+
}
9+
10+
class C1 extends P {
11+
public protected(set) mixed $foo = 1;
12+
}
13+
14+
class C2 extends P {
15+
public protected(set) mixed $foo;
16+
17+
static function foo($c) { return $c->foo += 1; }
18+
}
19+
20+
var_dump(C2::foo(new C1));
21+
22+
?>
23+
--EXPECT--
24+
int(43)

Zend/tests/gh19044.phpt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype
3+
--FILE--
4+
<?php
5+
6+
abstract class P {
7+
protected $foo;
8+
}
9+
10+
class C1 extends P {
11+
protected $foo = 1;
12+
}
13+
14+
class C2 extends P {
15+
protected $foo = 2;
16+
17+
static function foo($c) { return $c->foo; }
18+
}
19+
20+
var_dump(C2::foo(new C2));
21+
var_dump(C2::foo(new C1));
22+
23+
?>
24+
--EXPECT--
25+
int(2)
26+
int(1)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (common ancestor has a protected setter)
3+
--FILE--
4+
<?php
5+
6+
abstract class P {
7+
abstract public mixed $foo { get; }
8+
}
9+
10+
class C1 extends P {
11+
public protected(set) mixed $foo { get => 1; set {} }
12+
}
13+
14+
class GrandC1 extends C1 {
15+
public protected(set) mixed $foo { get => 2; set {} }
16+
}
17+
18+
class C2 extends C1 {
19+
static function foo($c) { return $c->foo += 1; }
20+
}
21+
22+
var_dump(C2::foo(new GrandC1));
23+
24+
?>
25+
--EXPECT--
26+
int(3)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (common ancestor does not have a setter)
3+
--FILE--
4+
<?php
5+
6+
abstract class P {
7+
abstract public mixed $foo { get; }
8+
}
9+
10+
class C1 extends P {
11+
public mixed $foo { get => 1; }
12+
}
13+
14+
class GrandC1 extends C1 {
15+
public protected(set) mixed $foo { get => 2; set {} }
16+
}
17+
18+
class C2 extends C1 {
19+
static function foo($c) { return $c->foo += 1; }
20+
}
21+
22+
var_dump(C2::foo(new GrandC1));
23+
24+
?>
25+
--EXPECT--
26+
int(3)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (abstract parent defining visibility only takes precedence)
3+
--FILE--
4+
<?php
5+
6+
abstract class P {
7+
abstract protected(set) mixed $foo { get; set; }
8+
}
9+
10+
class C1 extends P {
11+
public protected(set) mixed $foo { get => 2; set {} }
12+
}
13+
14+
class C2 extends P {
15+
public mixed $foo = 1;
16+
17+
static function foo($c) { return $c->foo += 1; }
18+
}
19+
20+
var_dump(C2::foo(new C1));
21+
22+
?>
23+
--EXPECT--
24+
int(3)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (abstract parent sets protected(set) with not having grandparent a setter - both inherit from parent)
3+
--FILE--
4+
<?php
5+
6+
abstract class GP {
7+
abstract mixed $foo { get; }
8+
}
9+
10+
abstract class P extends GP {
11+
abstract protected(set) mixed $foo { get; set; }
12+
}
13+
14+
class C1 extends P {
15+
public protected(set) mixed $foo { get => 2; set {} }
16+
}
17+
18+
class C2 extends P {
19+
public mixed $foo = 1;
20+
21+
static function foo($c) { return $c->foo += 1; }
22+
}
23+
24+
var_dump(C2::foo(new C1));
25+
26+
?>
27+
--EXPECT--
28+
int(3)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (abstract parent sets protected(set) with not having grandparent a setter - one inherits from grandparent)
3+
--FILE--
4+
<?php
5+
6+
abstract class GP {
7+
abstract mixed $foo { get; }
8+
}
9+
10+
abstract class P extends GP {
11+
abstract protected(set) mixed $foo { get; set; }
12+
}
13+
14+
class C1 extends P {
15+
public protected(set) mixed $foo { get => 2; set {} }
16+
}
17+
18+
class C2 extends GP {
19+
public mixed $foo = 1;
20+
21+
static function foo($c) { return $c->foo += 1; }
22+
}
23+
24+
var_dump(C2::foo(new C1));
25+
26+
?>
27+
--EXPECT--
28+
int(3)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (abstract parent has implicit set hook)
3+
--FILE--
4+
<?php
5+
6+
abstract class GP {
7+
public abstract mixed $foo { get; }
8+
}
9+
10+
class P extends GP {
11+
public protected(set) mixed $foo { get => $this->foo; }
12+
}
13+
14+
class C1 extends P {
15+
public protected(set) mixed $foo = 1;
16+
}
17+
18+
class C2 extends P {
19+
public protected(set) mixed $foo;
20+
21+
static function foo($c) { return $c->foo += 1; }
22+
}
23+
24+
var_dump(C2::foo(new C1));
25+
26+
?>
27+
--EXPECT--
28+
int(2)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
GH-19044: Protected properties must be scoped according to their prototype (hooks variation)
3+
--FILE--
4+
<?php
5+
6+
abstract class P {
7+
abstract protected $foo { get; }
8+
}
9+
10+
class C1 extends P {
11+
protected $foo = 1;
12+
}
13+
14+
class C2 extends P {
15+
protected $foo = 2;
16+
17+
static function foo($c) { return $c->foo; }
18+
}
19+
20+
var_dump(C2::foo(new C2));
21+
var_dump(C2::foo(new C1));
22+
23+
?>
24+
--EXPECT--
25+
int(2)
26+
int(1)

0 commit comments

Comments
 (0)