Skip to content

Commit 8df557a

Browse files
iluuu1994Crell
andauthored
[RFC] Asymmetric visibility v2 (phpGH-15063)
Co-authored-by: Larry Garfield <larry@garfieldtech.com>
1 parent fef55bc commit 8df557a

File tree

70 files changed

+1768
-155
lines changed

Some content is hidden

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

70 files changed

+1768
-155
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ PHP NEWS
1616
undefined). (Peter Kokot)
1717
. Fixed bug GH-15565 (--disable-ipv6 during compilation produces error
1818
EAI_SYSTEM not found). (nielsdos)
19+
. Implemented asymmetric visibility for properties. (ilutov)
1920

2021
- Date:
2122
. Fixed bug GH-13773 (DatePeriod not taking into account microseconds for end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Asymmetric visibility __set
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public private(set) string $bar;
8+
9+
public function setBar($bar) {
10+
$this->bar = $bar;
11+
}
12+
13+
public function unsetBar() {
14+
unset($this->bar);
15+
}
16+
17+
public function __set(string $name, mixed $value) {
18+
echo __CLASS__, '::', __METHOD__, "\n";
19+
}
20+
}
21+
22+
$foo = new Foo();
23+
try {
24+
$foo->bar = 'baz';
25+
} catch (Error $e) {
26+
echo $e->getMessage(), "\n";
27+
}
28+
29+
$foo->setBar('baz');
30+
try {
31+
$foo->bar = 'baz';
32+
} catch (Error $e) {
33+
echo $e->getMessage(), "\n";
34+
}
35+
36+
$foo->unsetBar();
37+
$foo->bar = 'baz';
38+
39+
?>
40+
--EXPECT--
41+
Cannot modify private(set) property Foo::$bar from global scope
42+
Cannot modify private(set) property Foo::$bar from global scope
43+
Foo::Foo::__set
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
--TEST--
2+
Asymmetric visibility __unset
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public private(set) string $bar;
8+
9+
public function setBar($bar) {
10+
$this->bar = $bar;
11+
}
12+
13+
public function unsetBar() {
14+
unset($this->bar);
15+
}
16+
17+
public function __unset($name) {
18+
echo __METHOD__, "\n";
19+
}
20+
}
21+
22+
function test($foo) {
23+
try {
24+
unset($foo->bar);
25+
} catch (Error $e) {
26+
echo $e->getMessage(), "\n";
27+
}
28+
}
29+
30+
$foo = new Foo();
31+
test($foo);
32+
33+
$foo->unsetBar();
34+
test($foo);
35+
36+
$foo->setBar('bar');
37+
test($foo);
38+
39+
$foo->unsetBar();
40+
test($foo);
41+
42+
?>
43+
--EXPECT--
44+
Cannot unset private(set) property Foo::$bar from global scope
45+
Foo::__unset
46+
Cannot unset private(set) property Foo::$bar from global scope
47+
Foo::__unset
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
private(set) protected(set) ast printing
3+
--INI--
4+
zend.assertions=1
5+
assert.exception=1
6+
--FILE--
7+
<?php
8+
9+
try {
10+
assert(function () {
11+
class Foo {
12+
public private(set) string $bar;
13+
public protected(set) string $baz;
14+
}
15+
} && false);
16+
} catch (Error $e) {
17+
echo $e->getMessage();
18+
}
19+
20+
?>
21+
--EXPECT--
22+
assert(function () {
23+
class Foo {
24+
public private(set) string $bar;
25+
public protected(set) string $baz;
26+
}
27+
28+
} && false)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Unset from __unset respects set visibility
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public private(set) int $a = 1;
8+
public function __construct() {
9+
unset($this->a);
10+
}
11+
}
12+
13+
class D extends C {
14+
public function __unset($name) {
15+
unset($this->a);
16+
}
17+
}
18+
19+
$c = new D();
20+
try {
21+
unset($c->a);
22+
} catch (Error $e) {
23+
echo $e->getMessage(), "\n";
24+
}
25+
var_dump($c);
26+
27+
?>
28+
--EXPECTF--
29+
Cannot unset private(set) property C::$a from scope D
30+
object(D)#%d (0) {
31+
["a"]=>
32+
uninitialized(int)
33+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Set from __set respects set visibility
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public private(set) int $a = 1;
8+
public function __construct() {
9+
unset($this->a);
10+
}
11+
}
12+
13+
class D extends C {
14+
public function __set($name, $value) {
15+
$this->a = $value;
16+
}
17+
}
18+
19+
$c = new D();
20+
try {
21+
$c->a = 2;
22+
} catch (Error $e) {
23+
echo $e->getMessage(), "\n";
24+
}
25+
var_dump($c);
26+
27+
?>
28+
--EXPECTF--
29+
Cannot modify private(set) property C::$a from scope D
30+
object(D)#%d (0) {
31+
["a"]=>
32+
uninitialized(int)
33+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
Explicitly unset property with a-vis still respects set visibility
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
public private(set) int $a = 1;
8+
public function __construct() {
9+
unset($this->a);
10+
}
11+
}
12+
13+
$c = new C();
14+
try {
15+
$c->a = 2;
16+
} catch (Error $e) {
17+
echo $e->getMessage(), "\n";
18+
}
19+
try {
20+
unset($c->a);
21+
} catch (Error $e) {
22+
echo $e->getMessage(), "\n";
23+
}
24+
25+
?>
26+
--EXPECT--
27+
Cannot modify private(set) property C::$a from global scope
28+
Cannot unset private(set) property C::$a from global scope
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Missing property initialization for private(set) constructor promoted property
3+
--FILE--
4+
<?php
5+
6+
class T {
7+
public function __construct(
8+
private(set) string $prop,
9+
) {}
10+
}
11+
var_dump(new T('Test'));
12+
13+
?>
14+
--EXPECTF--
15+
object(T)#%d (1) {
16+
["prop"]=>
17+
string(4) "Test"
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Asymmetric visibility in CPP with no type
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public function __construct(
8+
public private(set) $bar,
9+
) {}
10+
}
11+
12+
?>
13+
--EXPECTF--
14+
Fatal error: Property with asymmetric visibility Foo::$bar must have type in %s on line %d
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Asymmetric visibility private(set) CPP
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public function __construct(
8+
public private(set) string $bar,
9+
) {}
10+
11+
public function setBar($bar) {
12+
$this->bar = $bar;
13+
}
14+
}
15+
16+
$foo = new Foo('bar');
17+
var_dump($foo->bar);
18+
19+
try {
20+
$foo->bar = 'baz';
21+
} catch (Error $e) {
22+
echo $e->getMessage(), "\n";
23+
}
24+
25+
$foo->setBar('baz');
26+
var_dump($foo->bar);
27+
28+
?>
29+
--EXPECT--
30+
string(3) "bar"
31+
Cannot modify private(set) property Foo::$bar from global scope
32+
string(3) "baz"
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
--TEST--
2+
Asymmetric visibility protected(set) CPP
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public function __construct(
8+
public protected(set) string $bar,
9+
) {}
10+
11+
public function setBarPrivate($bar) {
12+
$this->bar = $bar;
13+
}
14+
}
15+
16+
class FooChild extends Foo {
17+
public function setBarProtected($bar) {
18+
$this->bar = $bar;
19+
}
20+
}
21+
22+
$foo = new FooChild('bar');
23+
var_dump($foo->bar);
24+
25+
try {
26+
$foo->bar = 'baz';
27+
} catch (Error $e) {
28+
echo $e->getMessage(), "\n";
29+
}
30+
31+
$foo->setBarPrivate('baz');
32+
var_dump($foo->bar);
33+
34+
$foo->setBarProtected('qux');
35+
var_dump($foo->bar);
36+
37+
?>
38+
--EXPECT--
39+
string(3) "bar"
40+
Cannot modify protected(set) property Foo::$bar from global scope
41+
string(3) "baz"
42+
string(3) "qux"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Asymmetric visibility private(get) protected(set) in CPP is not allowed
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
public function __construct(
8+
private protected(set) string $bar
9+
) {}
10+
}
11+
12+
?>
13+
--EXPECTF--
14+
Fatal error: Visibility of property Foo::$bar must not be weaker than set visibility in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Asymmetric visibility private(get) private(set) is allowed
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
private private(set) string $bar;
8+
}
9+
10+
?>
11+
===DONE===
12+
--EXPECT--
13+
===DONE===
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Asymmetric visibility private(get) protected(set) not allowed
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
private protected(set) string $bar;
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Visibility of property Foo::$bar must not be weaker than set visibility in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Asymmetric visibility protected(get) protected(set) is allowed
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
protected protected(set) string $bar;
8+
}
9+
10+
?>
11+
===DONE===
12+
--EXPECT--
13+
===DONE===

0 commit comments

Comments
 (0)