Skip to content

Commit 88bee04

Browse files
authored
Merge pull request #38 from xp-framework/refactor/context
Remove context from properties, methods, constructors and initializers
2 parents 7987576 + abe7c6f commit 88bee04

File tree

9 files changed

+39
-140
lines changed

9 files changed

+39
-140
lines changed

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

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -30,32 +30,25 @@ public function toString() {
3030
* Creates a new instance of the type this constructor belongs to
3131
*
3232
* @param var[] $args
33-
* @param ?string|?lang.XPClass|?lang.reflection.Type $context
3433
* @return object
3534
* @throws lang.reflection.InvocationFailed
3635
* @throws lang.reflection.CannotInstantiate
3736
*/
38-
public function newInstance(array $args= [], $context= null) {
37+
public function newInstance(array $args= []) {
3938
try {
4039
$pass= PHP_VERSION_ID < 80000 && $args ? self::pass($this->reflect, $args) : $args;
4140

4241
// Workaround for non-public constructors: Set accessible, then manually
4342
// invoke after creating an instance without invoking the constructor.
44-
if ($context && !$this->reflect->isPublic()) {
45-
if (Reflection::of($context)->is($this->class->name)) {
46-
$instance= $this->class->newInstanceWithoutConstructor();
47-
$this->reflect->setAccessible(true);
48-
$this->reflect->invokeArgs($instance, $pass);
49-
return $instance;
50-
}
43+
if (!$this->reflect->isPublic()) {
44+
$instance= $this->class->newInstanceWithoutConstructor();
45+
$this->reflect->setAccessible(true);
46+
$this->reflect->invokeArgs($instance, $pass);
47+
return $instance;
48+
} else {
49+
return $this->class->newInstanceArgs($pass);
5150
}
52-
53-
return $this->class->newInstanceArgs($pass);
54-
} catch (ArgumentCountError $e) {
55-
throw new CannotInstantiate($this->class, $e);
56-
} catch (TypeError $e) {
57-
throw new CannotInstantiate($this->class, $e);
58-
} catch (ReflectionException $e) {
51+
} catch (ReflectionException|ArgumentCountError|TypeError $e) {
5952
throw new CannotInstantiate($this->class, $e);
6053
} catch (Throwable $e) {
6154

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

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

3-
use ArgumentCountError, Error, ReflectionException, Throwable, TypeError;
3+
use ArgumentCountError, Error, ReflectionException, ReflectionFunction, Throwable, TypeError;
44
use lang\Reflection;
55

66
/**
@@ -13,7 +13,7 @@ class Initializer extends Routine implements Instantiation {
1313
private $class, $function;
1414

1515
static function __static() {
16-
self::$NOOP= new \ReflectionFunction(function() { });
16+
self::$NOOP= new ReflectionFunction(function() { });
1717
}
1818

1919
/**
@@ -41,12 +41,11 @@ public function compoundName(): string { return strtr($this->class->name, '\\',
4141
* Creates a new instance of the type this constructor belongs to
4242
*
4343
* @param var[] $args
44-
* @param ?string|?lang.XPClass|?lang.reflection.Type $context
4544
* @return object
4645
* @throws lang.reflection.InvocationFailed
4746
* @throws lang.reflection.CannotInstantiate
4847
*/
49-
public function newInstance(array $args= [], $context= null) {
48+
public function newInstance(array $args= []) {
5049
try {
5150
$instance= $this->class->newInstanceWithoutConstructor();
5251
} catch (ReflectionException $e) {
@@ -57,13 +56,9 @@ public function newInstance(array $args= [], $context= null) {
5756

5857
try {
5958
$pass= PHP_VERSION_ID < 80000 && $args ? Routine::pass($this->reflect, $args) : $args;
60-
$this->function->__invoke($instance, $pass, $context);
59+
$this->function->__invoke($instance, $pass);
6160
return $instance;
62-
} catch (ArgumentCountError $e) {
63-
throw new CannotInstantiate($this->class, $e);
64-
} catch (TypeError $e) {
65-
throw new CannotInstantiate($this->class, $e);
66-
} catch (ReflectionException $e) {
61+
} catch (ReflectionException|ArgumentCountError|TypeError $e) {
6762
throw new CannotInstantiate($this->class, $e);
6863
} catch (Throwable $e) {
6964

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ interface Instantiation {
77
* Creates a new instance of the type this constructor belongs to
88
*
99
* @param var[] $args
10-
* @param ?string|?lang.XPClass|?lang.reflection.Type $context
1110
* @return object
1211
* @throws lang.reflection.InvocationFailed
1312
* @throws lang.reflection.CannotInstantiate
1413
*/
15-
public function newInstance(array $args= [], $context= null);
14+
public function newInstance(array $args= []);
1615
}

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

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,24 +44,14 @@ public function closure($instance= null) {
4444
*
4545
* @param ?object $instance
4646
* @param var[] $args
47-
* @param ?string|?lang.XPClass|?lang.reflection.Type $context
4847
* @return var
4948
* @throws lang.reflection.CannotInvoke if prerequisites to the invocation fail
5049
* @throws lang.reflection.InvocationFailed if invocation raises an exception
5150
*/
52-
public function invoke($instance, $args= [], $context= null) {
53-
54-
// Only allow invoking non-public methods when given a compatible context
55-
if (!$this->reflect->isPublic()) {
56-
if ($context && Reflection::type($context)->is($this->reflect->class)) {
57-
$this->reflect->setAccessible(true);
58-
} else {
59-
throw new CannotInvoke($this, new ReflectionException('Trying to invoke non-public method'));
60-
}
61-
}
62-
51+
public function invoke(?object $instance, $args= []) {
6352
try {
6453
$pass= PHP_VERSION_ID < 80000 && $args ? self::pass($this->reflect, $args) : $args;
54+
$this->reflect->setAccessible(true);
6555
return $this->reflect->invokeArgs($instance, $pass);
6656
} catch (ReflectionException|ArgumentCountError|TypeError $e) {
6757
throw new CannotInvoke($this, $e);

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

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,18 @@ public function constraint() {
4242
* Gets this property's value
4343
*
4444
* @param ?object $instance
45-
* @param ?string|?lang.XPClass|?lang.reflection.Type $context
4645
* @return var
4746
* @throws lang.reflection.CannotAccess
47+
* @throws lang.reflection.AccessingFailed if getting raises an exception
4848
*/
49-
public function get($instance, $context= null) {
50-
51-
// Only allow reading non-public properties when given a compatible context
52-
if (!$this->reflect->isPublic()) {
53-
if ($context && Reflection::of($context)->is($this->reflect->getDeclaringClass()->name)) {
54-
$this->reflect->setAccessible(true);
55-
} else {
56-
throw new CannotAccess($this, new ReflectionException('Trying to read non-public property'));
57-
}
58-
}
59-
49+
public function get(?object $instance) {
6050
try {
51+
$this->reflect->setAccessible(true);
6152
return $this->reflect->getValue($instance);
6253
} catch (ReflectionException $e) {
6354
throw new CannotAccess($this, $e);
55+
} catch (Throwable $e) {
56+
throw new AccessingFailed($this, $e);
6457
}
6558
}
6659

@@ -69,23 +62,13 @@ public function get($instance, $context= null) {
6962
*
7063
* @param ?object $instance
7164
* @param var $value
72-
* @param ?string|?lang.XPClass|?lang.reflection.Type $context
7365
* @return var The given value
7466
* @throws lang.reflection.CannotAccess
75-
* @throws lang.reflection.AccessFailed if setting raises an exception
67+
* @throws lang.reflection.AccessingFailed if setting raises an exception
7668
*/
77-
public function set($instance, $value, $context= null) {
78-
79-
// Only allow reading non-public properties when given a compatible context
80-
if (!$this->reflect->isPublic()) {
81-
if ($context && Reflection::of($context)->is($this->reflect->getDeclaringClass()->name)) {
82-
$this->reflect->setAccessible(true);
83-
} else {
84-
throw new CannotAccess($this, new ReflectionException('Trying to write non-public property'));
85-
}
86-
}
87-
69+
public function set(?object $instance, $value) {
8870
try {
71+
$this->reflect->setAccessible(true);
8972
$this->reflect->setValue($instance, $value);
9073
return $value;
9174
} catch (ReflectionException $e) {

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,15 +162,13 @@ public function initializer($function) {
162162
return new Initializer($this->reflect);
163163
} else if ($function instanceof \Closure) {
164164
$reflect= new ReflectionFunction($function);
165-
return new Initializer($this->reflect, $reflect, function($instance, $args, $context) use($function) {
165+
return new Initializer($this->reflect, $reflect, function($instance, $args) use($function) {
166166
return $function->call($instance, ...$args);
167167
});
168168
} else if ($this->reflect->hasMethod($function)) {
169169
$reflect= $this->reflect->getMethod($function);
170-
return new Initializer($this->reflect, $reflect, function($instance, $args, $context) use($reflect) {
171-
if ($context && !$reflect->isPublic() && Reflection::of($context)->isInstance($instance)) {
172-
$reflect->setAccessible(true);
173-
}
170+
return new Initializer($this->reflect, $reflect, function($instance, $args) use($reflect) {
171+
$reflect->setAccessible(true);
174172
return $reflect->invokeArgs($instance, $args);
175173
});
176174
}

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

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,6 @@ public function newInstance_cannot_instantiate_using_non_public_constructor($mod
9292
$t->newInstance();
9393
}
9494

95-
#[Test, Expect(CannotInstantiate::class), Values(['private', 'protected'])]
96-
public function constructor_cannot_instantiate_using_non_public_constructor($modifier) {
97-
$t= $this->declare('{ '.$modifier.' function __construct() { } }');
98-
$t->constructor()->newInstance();
99-
}
100-
10195
#[Test, Values(['private', 'protected'])]
10296
public function instantiate_with_non_public_constructor_in_context($modifier) {
10397
$t= $this->declare('{
@@ -113,12 +107,6 @@ public function instantiate_with_constructor_promotion() {
113107
Assert::equals($this, $t->constructor()->newInstance([$this])->value);
114108
}
115109

116-
#[Test, Expect(CannotInstantiate::class)]
117-
public function cannot_instantiate_with_private_constructor_in_incorrect_context() {
118-
$t= $this->declare('{ private function __construct() { } }');
119-
$t->constructor()->newInstance([], typeof($this));
120-
}
121-
122110
#[Test, Expect(CannotInstantiate::class)]
123111
public function interfaces_cannot_be_instantiated() {
124112
Reflection::type(Runnable::class)->newInstance();

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

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

33
use lang\reflection\{CannotInvoke, InvocationFailed};
4-
use lang\{CommandLine, IllegalAccessException, Reflection, Runnable};
4+
use lang\{CommandLine, IllegalAccessException, Reflection, Runnable, IllegalStateException};
55
use test\{Assert, AssertionFailedError, Before, Expect, Test, Values};
66

77
class InvocationTest {
@@ -32,22 +32,10 @@ public function invoke_instance_method_from($context) {
3232
Assert::equals('External', $method->invoke($this->fixtures[$context]->newInstance(), []));
3333
}
3434

35-
#[Test, Values([['friend'], ['internal']]), Expect(CannotInvoke::class)]
36-
public function cannot_invoke_non_public_method_by_default($method) {
37-
$method= $this->fixtures['parent']->method($method);
38-
$method->invoke($this->fixtures['parent']->newInstance(), []);
39-
}
40-
4135
#[Test, Values([['parent', 'parent'], ['child', 'parent'], ['parent', 'child']])]
4236
public function invoke_private_method_in_context($instance, $context) {
4337
$method= $this->fixtures['parent']->method('internal');
44-
Assert::equals('Internal', $method->invoke($this->fixtures[$instance]->newInstance(), [], $this->fixtures[$context]));
45-
}
46-
47-
#[Test, Expect(CannotInvoke::class)]
48-
public function cannot_invoke_private_method_in_incorrect_context() {
49-
$method= $this->fixtures['parent']->method('internal');
50-
$method->invoke($this->fixtures['parent']->newInstance(), [], typeof($this));
38+
Assert::equals('Internal', $method->invoke($this->fixtures[$instance]->newInstance(), []));
5139
}
5240

5341
#[Test, Expect(CannotInvoke::class)]
@@ -137,11 +125,11 @@ public function invocation_failed_target() {
137125
}
138126

139127
#[Test]
140-
public function cannot_invoke_target() {
141-
$t= $this->declare('{ private static function fixture() { } }');
128+
public function cannot_invoke_exceptions_target_member() {
129+
$t= $this->declare('{ private static function fixture($a) { } }');
142130
try {
143131
$t->method('fixture')->invoke(null, []);
144-
throw new AssertionFailedError('No exception was raised');
132+
throw new IllegalStateException('No exception was raised');
145133
} catch (CannotInvoke $expected) {
146134
Assert::equals($t->method('fixture'), $expected->target());
147135
}

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

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

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

88
class PropertiesTest {
99
use TypeDefinition;
@@ -79,44 +79,20 @@ public function set_static() {
7979
Assert::equals('Modified', $class::$fixture);
8080
}
8181

82-
#[Test, Expect(CannotAccess::class)]
83-
public function cannot_read_private_by_default() {
84-
$type= $this->declare('{ private static $fixture = "Test"; }');
85-
$type->property('fixture')->get(null);
86-
}
87-
88-
#[Test, Expect(CannotAccess::class)]
89-
public function cannot_write_private_by_default() {
90-
$type= $this->declare('{ private static $fixture = "Test"; }');
91-
$type->property('fixture')->set(null, 'Modified');
92-
}
93-
94-
#[Test, Expect(CannotAccess::class)]
95-
public function cannot_read_private_with_incorrect_context() {
96-
$type= $this->declare('{ private static $fixture = "Test"; }');
97-
$type->property('fixture')->get(null, typeof($this));
98-
}
99-
100-
#[Test, Expect(CannotAccess::class)]
101-
public function cannot_write_private_with_incorrect_context() {
102-
$type= $this->declare('{ private static $fixture = "Test"; }');
103-
$type->property('fixture')->set(null, 'Modified', typeof($this));
104-
}
105-
10682
#[Test, Expect(AccessingFailed::class)]
10783
public function type_mismatch() {
10884
$type= $this->declare('{ private static array $fixture; }');
109-
$type->property('fixture')->set(null, 1, $type);
85+
$type->property('fixture')->set(null, 1);
11086
}
11187

11288
#[Test]
11389
public function private_instance_roundtrip() {
11490
$type= $this->declare('{ private $fixture = "Test"; }');
11591
$instance= $type->newInstance();
11692
$property= $type->properties()->named('fixture');
117-
$property->set($instance, 'Modified', $type);
93+
$property->set($instance, 'Modified');
11894

119-
Assert::equals('Modified', $property->get($instance, $type));
95+
Assert::equals('Modified', $property->get($instance));
12096
}
12197

12298
#[Test]
@@ -242,7 +218,7 @@ public function string_representation_with_union_type_declaration() {
242218
}
243219

244220
#[Test]
245-
public function accessing_failed_target() {
221+
public function set_accessing_failed_exceptions_target_member() {
246222
$t= $this->declare('{ public static array $fixture; }');
247223
try {
248224
$t->property('fixture')->set(null, 1);
@@ -251,15 +227,4 @@ public function accessing_failed_target() {
251227
Assert::equals($t->property('fixture'), $expected->target());
252228
}
253229
}
254-
255-
#[Test]
256-
public function cannot_access_target() {
257-
$t= $this->declare('{ private static $fixture; }');
258-
try {
259-
$t->property('fixture')->get(null);
260-
throw new AssertionFailedError('No exception was raised');
261-
} catch (CannotAccess $expected) {
262-
Assert::equals($t->property('fixture'), $expected->target());
263-
}
264-
}
265230
}

0 commit comments

Comments
 (0)