Skip to content

Commit ce2ba92

Browse files
[RFC] Friends
1 parent 794a35c commit ce2ba92

52 files changed

Lines changed: 1650 additions & 47 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
--TEST--
2+
Friends: anonymous classes can have friends
3+
--FILE--
4+
<?php
5+
6+
class Bar {
7+
public static function testAccess(object $obj) {
8+
$obj::protectedStatic();
9+
echo "\n";
10+
$obj::privateStatic();
11+
echo "\n";
12+
$obj->protectedInstance();
13+
echo "\n";
14+
$obj->privateInstance();
15+
echo "\n";
16+
$obj->protectedProp = 1;
17+
$obj->privateProp = 2;
18+
var_dump($obj);
19+
var_dump($obj::FIRST);
20+
var_dump($obj::SECOND);
21+
}
22+
}
23+
24+
$obj = new class () {
25+
friend Bar;
26+
27+
protected $protectedProp;
28+
private $privateProp;
29+
30+
protected const FIRST = 1;
31+
private const SECOND = 2;
32+
33+
protected static function protectedStatic() {
34+
echo __METHOD__ . "() called, backtrace:\n";
35+
debug_print_backtrace();
36+
}
37+
38+
private static function privateStatic() {
39+
echo __METHOD__ . "() called, backtrace:\n";
40+
debug_print_backtrace();
41+
}
42+
43+
protected function protectedInstance() {
44+
echo __METHOD__ . "() called, backtrace:\n";
45+
debug_print_backtrace();
46+
}
47+
48+
private function privateInstance() {
49+
echo __METHOD__ . "() called, backtrace:\n";
50+
debug_print_backtrace();
51+
}
52+
};
53+
54+
Bar::testAccess($obj);
55+
56+
?>
57+
--EXPECTF--
58+
class@anonymous%s:%d$0::protectedStatic() called, backtrace:
59+
#0 %s(%d): class@anonymous::protectedStatic()
60+
#1 %s(%d): Bar::testAccess(Object(class@anonymous))
61+
62+
class@anonymous%s:%d$0::privateStatic() called, backtrace:
63+
#0 %s(%d): class@anonymous::privateStatic()
64+
#1 %s(%d): Bar::testAccess(Object(class@anonymous))
65+
66+
class@anonymous%s:%d$0::protectedInstance() called, backtrace:
67+
#0 %s(%d): class@anonymous->protectedInstance()
68+
#1 %s(%d): Bar::testAccess(Object(class@anonymous))
69+
70+
class@anonymous%s:%d$0::privateInstance() called, backtrace:
71+
#0 %s(%d): class@anonymous->privateInstance()
72+
#1 %s(%d): Bar::testAccess(Object(class@anonymous))
73+
74+
object(class@anonymous)#1 (2) {
75+
["protectedProp":protected]=>
76+
int(1)
77+
["privateProp":"class@anonymous":private]=>
78+
int(2)
79+
}
80+
int(1)
81+
int(2)
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Friends: AST printing
3+
--FILE--
4+
<?php
5+
6+
try {
7+
assert(function () {
8+
class Foo {
9+
friend Bar;
10+
}
11+
} && false);
12+
} catch (Error $e) {
13+
echo $e->getMessage();
14+
}
15+
16+
?>
17+
--EXPECT--
18+
assert(function () {
19+
class Foo {
20+
friend Bar;
21+
}
22+
23+
} && false)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
--TEST--
2+
Friends: allows access to cloning
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
friend Bar;
8+
9+
private function __clone() {
10+
echo __METHOD__ . "() called, backtrace:\n";
11+
debug_print_backtrace();
12+
}
13+
14+
}
15+
16+
class Bar {
17+
public static function testCloneAccess() {
18+
$f = new Foo();
19+
$g = clone $f;
20+
}
21+
}
22+
23+
// Confirm that the presence of a friend does not negate normal visibility
24+
// enforcement for non friends
25+
$f = new Foo();
26+
try {
27+
clone $f;
28+
} catch (Error $e) {
29+
echo $e . "\n";
30+
}
31+
32+
echo "\n\n-----\n\n";
33+
34+
// But friend works
35+
Bar::testCloneAccess();
36+
37+
?>
38+
--EXPECTF--
39+
Error: Call to private method Foo::__clone() from global scope in %s:%d
40+
Stack trace:
41+
#0 {main}
42+
43+
44+
-----
45+
46+
Foo::__clone() called, backtrace:
47+
#0 %s(%d): Foo->__clone()
48+
#1 %s(%d): Bar::testCloneAccess()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Friends: cannot be used on interfaces
3+
--FILE--
4+
<?php
5+
6+
interface Foo {
7+
friend Bar;
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot add friends to interfaces. Bar is used in Foo 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+
Friends: same friend cannot be used multiple times
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
friend Bar;
8+
friend Bar;
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Cannot add Bar as a friend of Foo multiple times. 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+
Friends: same friend cannot be used multiple times (case insensitive)
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
friend Bar;
8+
friend BAR;
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Cannot add BAR as a friend of Foo multiple times. in %s on line %d
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
Friends: same friend cannot be used multiple times (after name resolution)
3+
--FILE--
4+
<?php
5+
6+
use SomeNamespace\Bar;
7+
use SomeNamespace\Bar as Baz;
8+
9+
class Foo {
10+
friend Bar;
11+
friend Baz;
12+
}
13+
14+
?>
15+
--EXPECTF--
16+
Fatal error: Cannot add SomeNamespace\Bar as a friend of Foo multiple times. in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Friends: 'parent' cannot be used as a friend name
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
friend parent;
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot use "parent" as friend name, as it is reserved in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Friends: 'self' cannot be used as a friend name
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
friend self;
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot use "self" as friend name, as it is reserved in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Friends: 'static' cannot be used as a friend name
3+
--FILE--
4+
<?php
5+
6+
class Foo {
7+
friend static;
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot use "static" as friend name, as it is reserved in %s on line %d

0 commit comments

Comments
 (0)