Skip to content

Commit 5813384

Browse files
committed
Add optional hook parameter to Property::modifiers()
1 parent 68c0562 commit 5813384

File tree

3 files changed

+89
-14
lines changed

3 files changed

+89
-14
lines changed

src/main/php/lang/reflection/Modifiers.class.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ class Modifiers implements Value {
1515
const IS_PROTECTED = MODIFIER_PROTECTED;
1616
const IS_PRIVATE = MODIFIER_PRIVATE;
1717
const IS_READONLY = MODIFIER_READONLY;
18-
const IS_PRIVATE_SET = 0x0400;
18+
const IS_PUBLIC_SET = 0x0400;
1919
const IS_PROTECTED_SET = 0x0800;
20-
const IS_PUBLIC_SET = 0x1000;
20+
const IS_PRIVATE_SET = 0x1000;
2121
const IS_NATIVE = 0x10000;
2222

2323
private static $names= [
@@ -29,9 +29,9 @@ class Modifiers implements Value {
2929
'abstract' => self::IS_ABSTRACT,
3030
'native' => self::IS_NATIVE,
3131
'readonly' => self::IS_READONLY,
32-
'private(set)' => self::IS_PRIVATE_SET,
33-
'protected(set)' => self::IS_PROTECTED_SET,
3432
'public(set)' => self::IS_PUBLIC_SET,
33+
'protected(set)' => self::IS_PROTECTED_SET,
34+
'private(set)' => self::IS_PRIVATE_SET,
3535
];
3636
private $bits;
3737

@@ -117,7 +117,7 @@ public function isReadonly() { return 0 !== ($this->bits & self::IS_READONLY); }
117117
/**
118118
* Gets whether these modifiers are public in regard to the specified hook
119119
*
120-
* @param ?string $hook
120+
* @param string $hook
121121
* @return bool
122122
* @throws lang.IllegalArgumentException
123123
*/
@@ -132,7 +132,7 @@ public function isPublic($hook= 'get') {
132132
/**
133133
* Gets whether these modifiers are protected in regard to the specified hook
134134
*
135-
* @param ?string $hook
135+
* @param string $hook
136136
* @return bool
137137
* @throws lang.IllegalArgumentException
138138
*/
@@ -147,7 +147,7 @@ public function isProtected($hook= 'get') {
147147
/**
148148
* Gets whether these modifiers are private in regard to the specified hook
149149
*
150-
* @param ?string $hook
150+
* @param string $hook
151151
* @return bool
152152
* @throws lang.IllegalArgumentException
153153
*/

src/main/php/lang/reflection/Property.class.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php namespace lang\reflection;
22

33
use ReflectionException, ReflectionUnionType, Throwable;
4-
use lang\{Reflection, XPClass, Type, VirtualProperty, TypeUnion};
4+
use lang\{Reflection, XPClass, Type, VirtualProperty, TypeUnion, IllegalArgumentException};
55

66
/**
77
* Reflection for a single property
@@ -38,6 +38,29 @@ public function constraint() {
3838
return new Constraint($t ?? Type::$VAR, $present);
3939
}
4040

41+
/**
42+
* Gets whether these modifiers are public in regard to the specified hook
43+
*
44+
* @param ?string $hook Optionally, filter for specified hook only
45+
* @return lang.reflection.Modifiers
46+
* @throws lang.IllegalArgumentException
47+
*/
48+
public function modifiers($hook= null) {
49+
static $set= [
50+
Modifiers::IS_PUBLIC_SET => Modifiers::IS_PUBLIC,
51+
Modifiers::IS_PROTECTED_SET => Modifiers::IS_PROTECTED,
52+
Modifiers::IS_PRIVATE_SET => Modifiers::IS_PRIVATE,
53+
];
54+
55+
$bits= $this->reflect->getModifiers();
56+
switch ($hook) {
57+
case null: return new Modifiers($bits);
58+
case 'get': return new Modifiers($bits & ~0x1c00);
59+
case 'set': return new Modifiers($set[$bits & 0x1c00] ?? $bits);
60+
default: throw new IllegalArgumentException('Unknown hook '.$hook);
61+
}
62+
}
63+
4164
/**
4265
* Gets this property's value
4366
*

src/test/php/lang/reflection/unittest/PropertiesTest.class.php

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
<?php namespace lang\reflection\unittest;
22

33
use lang\reflection\{AccessingFailed, CannotAccess, Constraint, Modifiers};
4-
use lang\{Primitive, Type, TypeIntersection, TypeUnion, XPClass, IllegalStateException};
5-
use test\verify\Runtime;
4+
use lang\{Primitive, Type, TypeIntersection, TypeUnion, XPClass, IllegalArgumentException};
5+
use test\verify\{Condition, Runtime};
66
use test\{Action, Assert, Expect, Test, Values};
77

88
class PropertiesTest {
99
use TypeDefinition;
1010

11+
private static $ASYMMETRIC;
12+
13+
static function __static() {
14+
self::$ASYMMETRIC= method_exists(\ReflectionProperty::class, 'isPrivateSet');
15+
}
16+
1117
#[Test]
1218
public function name() {
1319
Assert::equals('fixture', $this->declare('{ public $fixture; }')->property('fixture')->name());
@@ -27,6 +33,27 @@ public function modifiers() {
2733
);
2834
}
2935

36+
#[Test, Values(['public', 'protected', 'private'])]
37+
public function get_modifiers($modifier) {
38+
Assert::equals(
39+
new Modifiers($modifier),
40+
$this->declare('{ '.$modifier.' $fixture; }')->property('fixture')->modifiers('get')
41+
);
42+
}
43+
44+
#[Test, Values(['public', 'protected', 'private'])]
45+
public function set_modifiers($modifier) {
46+
Assert::equals(
47+
new Modifiers($modifier),
48+
$this->declare('{ '.$modifier.' $fixture; }')->property('fixture')->modifiers('set')
49+
);
50+
}
51+
52+
#[Test, Expect(IllegalArgumentException::class)]
53+
public function modifiers_unknown_hook() {
54+
$this->declare('{ private $fixture; }')->property('fixture')->modifiers('@unknown');
55+
}
56+
3057
#[Test]
3158
public function no_comment() {
3259
Assert::null($this->declare('{ private $fixture; }')->property('fixture')->comment());
@@ -228,12 +255,37 @@ public function set_accessing_failed_exceptions_target_member() {
228255
}
229256
}
230257

231-
#[Test, Runtime(php: '>=8.4')]
232-
public function asymmetric_visibility() {
233-
$t= $this->declare('{ public private(set) string $fixture; }');
258+
#[Test, Condition(assert: 'self::$ASYMMETRIC'), Values(['public protected(set)', 'public private(set)', 'protected private(set)'])]
259+
public function asymmetric_visibility($modifiers) {
260+
$t= $this->declare('{ '.$modifiers.' int $fixture; }');
234261
Assert::equals(
235-
'public private(set) string $name',
262+
$modifiers.' int $fixture',
236263
$t->property('fixture')->toString()
237264
);
238265
}
266+
267+
#[Test, Condition(assert: 'self::$ASYMMETRIC'), Values(['public', 'protected', 'private'])]
268+
public function set_implicit_when_same_as_get($modifier) {
269+
$t= $this->declare('{ '.$modifier.' '.$modifier.'(set) int $fixture; }');
270+
Assert::equals(
271+
$modifier.' int $fixture',
272+
$t->property('fixture')->toString()
273+
);
274+
}
275+
276+
#[Test, Condition(assert: 'self::$ASYMMETRIC'), Values(['public', 'protected', 'private'])]
277+
public function asymmetric_get($modifier) {
278+
Assert::equals(
279+
new Modifiers($modifier),
280+
$this->declare('{ '.$modifier.' private(set) int $fixture; }')->property('fixture')->modifiers('get')
281+
);
282+
}
283+
284+
#[Test, Condition(assert: 'self::$ASYMMETRIC'), Values(['public', 'protected', 'private'])]
285+
public function asymmetric_set($modifier) {
286+
Assert::equals(
287+
new Modifiers($modifier),
288+
$this->declare('{ public '.$modifier.'(set) int $fixture; }')->property('fixture')->modifiers('set')
289+
);
290+
}
239291
}

0 commit comments

Comments
 (0)