-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Basic accessors implementation (WIP) #6873
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fd951b9
6a7269b
6f6f4a2
bce7dda
484dfa9
672b615
a051fc1
19bb004
aa1abc9
e3145b4
11aafaa
d2c177d
36dff63
ad8916d
4c46fb1
a94d2cb
f982549
afcd945
a467ae1
f518ce0
f4f07fd
a8b8d08
7af517f
5a49974
afddb9d
d5e6198
af100cc
b79cbdb
afa6e7e
17defb4
8f5ad8f
373f453
4514702
976f2db
04dad4a
1857bb9
5069793
2a2880b
00323ab
91ca074
eb70521
e97adc6
a151ec5
43d2b5c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--TEST-- | ||
Abstract accessors | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
public $prop { | ||
abstract get; | ||
set { echo __METHOD__, "()\n"; } | ||
} | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Class Test contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Test::$prop::get) in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--TEST-- | ||
Whole property can be marked abstract, but must use accessors | ||
--FILE-- | ||
<?php | ||
|
||
abstract class A { | ||
abstract public $prop { get; set; } | ||
} | ||
|
||
class B extends A { | ||
public $prop { get; set; } | ||
} | ||
|
||
?> | ||
===DONE=== | ||
--EXPECT-- | ||
===DONE=== |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--TEST-- | ||
Abstract property with abstract accessor | ||
--FILE-- | ||
<?php | ||
|
||
class C { | ||
abstract public $prop { abstract get; } | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Accessor on abstract property cannot be explicitly abstract in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--TEST-- | ||
Abstract property not implemented | ||
--FILE-- | ||
<?php | ||
|
||
class A { | ||
abstract public $prop { get; set; } | ||
} | ||
|
||
class B extends A { | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Class A contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (A::$prop::get, A::$prop::set) in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
--TEST-- | ||
Basic auto-generated accessors | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
public $prop { get; private set; } | ||
|
||
public function __construct() { | ||
$this->prop = 42; | ||
$this->prop = 24; | ||
} | ||
} | ||
|
||
$test = new Test; | ||
try { | ||
$test->prop = 12; | ||
} catch (Error $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
var_dump($test->prop); | ||
var_dump(isset($test->prop)); | ||
try { | ||
unset($test->prop); | ||
} catch (Error $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
?> | ||
--EXPECT-- | ||
Call to private accessor Test::$prop::set() from global scope | ||
int(24) | ||
bool(true) | ||
Cannot unset accessor property Test::$prop |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
--TEST-- | ||
Basic accessor syntax | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
public $prop1 { get; set; } | ||
public $prop2 { | ||
get { } | ||
private set { } | ||
} | ||
public $prop3 = 1 { get; private set; } | ||
} | ||
|
||
?> | ||
--EXPECT-- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
--TEST-- | ||
By-ref getter with a typed property | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
public array $prop = [] { &get; set; } | ||
} | ||
|
||
$test = new Test; | ||
$test->prop[] = 42; | ||
var_dump($test->prop); | ||
$ref =& $test->prop; | ||
$ref = [1, 2, 3]; | ||
var_dump($test->prop); | ||
|
||
try { | ||
$ref = 42; | ||
} catch (Error $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
|
||
?> | ||
--EXPECT-- | ||
array(1) { | ||
[0]=> | ||
int(42) | ||
} | ||
array(3) { | ||
[0]=> | ||
int(1) | ||
[1]=> | ||
int(2) | ||
[2]=> | ||
int(3) | ||
} | ||
Cannot assign int to reference held by property Test::$prop of type array |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
--TEST-- | ||
Test caching of accessor property kind | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
private $_prop; | ||
public $prop { | ||
&get { echo __METHOD__, "\n"; return $this->_prop; } | ||
set { echo __METHOD__, "\n"; $this->_prop = $value; } | ||
} | ||
} | ||
|
||
function doTest(Test $test) { | ||
$test->prop; | ||
$test->prop = 1; | ||
$test->prop += 1; | ||
$test->prop = []; | ||
$test->prop[] = 1; | ||
isset($test->prop); | ||
isset($test->prop[0]); | ||
try { | ||
unset($test->prop); | ||
} catch (Error $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
} | ||
|
||
$test = new Test; | ||
$test->dyn = 1; | ||
doTest($test); | ||
echo "\n"; | ||
doTest($test); | ||
|
||
?> | ||
--EXPECT-- | ||
Test::$prop::get | ||
Test::$prop::set | ||
Test::$prop::get | ||
Test::$prop::set | ||
Test::$prop::set | ||
Test::$prop::get | ||
Test::$prop::get | ||
Test::$prop::get | ||
Cannot unset accessor property Test::$prop | ||
|
||
Test::$prop::get | ||
Test::$prop::set | ||
Test::$prop::get | ||
Test::$prop::set | ||
Test::$prop::set | ||
Test::$prop::get | ||
Test::$prop::get | ||
Test::$prop::get | ||
Cannot unset accessor property Test::$prop |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
--TEST-- | ||
Purely virtual accessors cannot have default value | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
private $_prop; | ||
public $prop = 0 { | ||
get { return $this->_prop; } | ||
set { $this->_prop = $value; } | ||
} | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Cannot specify default value for property with explicit accessors in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
--TEST-- | ||
Dumping object with accessors | ||
--FILE-- | ||
<?php | ||
|
||
// The dump always only shows the contents of backing properties, | ||
// not any computed properties. | ||
class Test { | ||
public $prop = 1; | ||
public $prop2 = 2 { get; set; } | ||
public $prop3 { | ||
get { return 42; } | ||
} | ||
} | ||
|
||
$test = new Test; | ||
var_dump($test); | ||
var_dump(get_object_vars($test)); | ||
var_dump((array) $test); | ||
|
||
foreach ($test as $prop => $value) { | ||
echo "$prop => $value\n"; | ||
} | ||
|
||
?> | ||
--EXPECT-- | ||
object(Test)#1 (2) { | ||
["prop"]=> | ||
int(1) | ||
["prop2"]=> | ||
int(2) | ||
} | ||
array(2) { | ||
["prop"]=> | ||
int(1) | ||
["prop2"]=> | ||
int(2) | ||
} | ||
array(2) { | ||
["prop"]=> | ||
int(1) | ||
["prop2"]=> | ||
int(2) | ||
} | ||
prop => 1 | ||
prop2 => 2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--TEST-- | ||
Cannot declare same accessor twice | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
public $prop { | ||
get {} | ||
get {} | ||
} | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Cannot redeclare accessor "get" in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
--TEST-- | ||
Test the case where the initializing property assignment fails | ||
--FILE-- | ||
<?php | ||
class Test { | ||
public int $prop { get; } | ||
} | ||
$b = new Test; | ||
try { | ||
$b->prop = "foo"; | ||
} catch (Error $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
try { | ||
$b->prop; | ||
} catch (Error $e) { | ||
echo $e->getMessage(), "\n"; | ||
} | ||
?> | ||
--EXPECT-- | ||
Cannot assign string to property Test::$prop of type int | ||
Property Test::$prop must not be accessed before initialization |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--TEST-- | ||
Final accessors | ||
--FILE-- | ||
<?php | ||
|
||
class A { | ||
public $prop { | ||
final get { return 42; } | ||
} | ||
} | ||
|
||
class B extends A { | ||
public $prop { | ||
get { return 24; } | ||
} | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Cannot override final accessor A::$prop::get() in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
--TEST-- | ||
Property cannot be both final and private | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
final private $prop; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm still reading this rfc - I guess that's consistent with private final methods recently being forbidden. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. I was against that change at the time, but now we have to follow suit... |
||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Property cannot be both final and private in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
--TEST-- | ||
Property itself may be marked final (accessor) | ||
--FILE-- | ||
<?php | ||
|
||
class A { | ||
public final $prop { get; set; } | ||
} | ||
|
||
class B extends A { | ||
public $prop { get; set; } | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Cannot override final property A::$prop in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
--TEST-- | ||
Property itself may be marked final (normal) | ||
--FILE-- | ||
<?php | ||
|
||
class A { | ||
public final $prop; | ||
} | ||
|
||
class B extends A { | ||
public $prop { get; set; } | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Cannot override final property A::$prop in %s on line %d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
--TEST-- | ||
Cannot make accessor explicitly final in final property | ||
--FILE-- | ||
<?php | ||
|
||
class Test { | ||
final public $prop { | ||
final get; | ||
final set; | ||
} | ||
} | ||
|
||
?> | ||
--EXPECTF-- | ||
Fatal error: Accessor on final property cannot be explicitly final in %s on line %d |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is allowed by C#, why such syntax is not supported? Supporting default values would be very helpful.