diff --git a/src/main/php/lang/reflection/Constructor.class.php b/src/main/php/lang/reflection/Constructor.class.php index 10194ca..2cd8d92 100755 --- a/src/main/php/lang/reflection/Constructor.class.php +++ b/src/main/php/lang/reflection/Constructor.class.php @@ -30,32 +30,25 @@ public function toString() { * Creates a new instance of the type this constructor belongs to * * @param var[] $args - * @param ?string|?lang.XPClass|?lang.reflection.Type $context * @return object * @throws lang.reflection.InvocationFailed * @throws lang.reflection.CannotInstantiate */ - public function newInstance(array $args= [], $context= null) { + public function newInstance(array $args= []) { try { $pass= PHP_VERSION_ID < 80000 && $args ? self::pass($this->reflect, $args) : $args; // Workaround for non-public constructors: Set accessible, then manually // invoke after creating an instance without invoking the constructor. - if ($context && !$this->reflect->isPublic()) { - if (Reflection::of($context)->is($this->class->name)) { - $instance= $this->class->newInstanceWithoutConstructor(); - $this->reflect->setAccessible(true); - $this->reflect->invokeArgs($instance, $pass); - return $instance; - } + if (!$this->reflect->isPublic()) { + $instance= $this->class->newInstanceWithoutConstructor(); + $this->reflect->setAccessible(true); + $this->reflect->invokeArgs($instance, $pass); + return $instance; + } else { + return $this->class->newInstanceArgs($pass); } - - return $this->class->newInstanceArgs($pass); - } catch (ArgumentCountError $e) { - throw new CannotInstantiate($this->class, $e); - } catch (TypeError $e) { - throw new CannotInstantiate($this->class, $e); - } catch (ReflectionException $e) { + } catch (ReflectionException|ArgumentCountError|TypeError $e) { throw new CannotInstantiate($this->class, $e); } catch (Throwable $e) { diff --git a/src/main/php/lang/reflection/Initializer.class.php b/src/main/php/lang/reflection/Initializer.class.php index 5015518..962c5a6 100755 --- a/src/main/php/lang/reflection/Initializer.class.php +++ b/src/main/php/lang/reflection/Initializer.class.php @@ -1,6 +1,6 @@ class->name, '\\', * Creates a new instance of the type this constructor belongs to * * @param var[] $args - * @param ?string|?lang.XPClass|?lang.reflection.Type $context * @return object * @throws lang.reflection.InvocationFailed * @throws lang.reflection.CannotInstantiate */ - public function newInstance(array $args= [], $context= null) { + public function newInstance(array $args= []) { try { $instance= $this->class->newInstanceWithoutConstructor(); } catch (ReflectionException $e) { @@ -57,13 +56,9 @@ public function newInstance(array $args= [], $context= null) { try { $pass= PHP_VERSION_ID < 80000 && $args ? Routine::pass($this->reflect, $args) : $args; - $this->function->__invoke($instance, $pass, $context); + $this->function->__invoke($instance, $pass); return $instance; - } catch (ArgumentCountError $e) { - throw new CannotInstantiate($this->class, $e); - } catch (TypeError $e) { - throw new CannotInstantiate($this->class, $e); - } catch (ReflectionException $e) { + } catch (ReflectionException|ArgumentCountError|TypeError $e) { throw new CannotInstantiate($this->class, $e); } catch (Throwable $e) { diff --git a/src/main/php/lang/reflection/Instantiation.class.php b/src/main/php/lang/reflection/Instantiation.class.php index 8893132..91fe895 100755 --- a/src/main/php/lang/reflection/Instantiation.class.php +++ b/src/main/php/lang/reflection/Instantiation.class.php @@ -7,10 +7,9 @@ interface Instantiation { * Creates a new instance of the type this constructor belongs to * * @param var[] $args - * @param ?string|?lang.XPClass|?lang.reflection.Type $context * @return object * @throws lang.reflection.InvocationFailed * @throws lang.reflection.CannotInstantiate */ - public function newInstance(array $args= [], $context= null); + public function newInstance(array $args= []); } \ No newline at end of file diff --git a/src/main/php/lang/reflection/Method.class.php b/src/main/php/lang/reflection/Method.class.php index 3b3d17b..c95dad4 100755 --- a/src/main/php/lang/reflection/Method.class.php +++ b/src/main/php/lang/reflection/Method.class.php @@ -44,24 +44,14 @@ public function closure($instance= null) { * * @param ?object $instance * @param var[] $args - * @param ?string|?lang.XPClass|?lang.reflection.Type $context * @return var * @throws lang.reflection.CannotInvoke if prerequisites to the invocation fail * @throws lang.reflection.InvocationFailed if invocation raises an exception */ - public function invoke($instance, $args= [], $context= null) { - - // Only allow invoking non-public methods when given a compatible context - if (!$this->reflect->isPublic()) { - if ($context && Reflection::type($context)->is($this->reflect->class)) { - $this->reflect->setAccessible(true); - } else { - throw new CannotInvoke($this, new ReflectionException('Trying to invoke non-public method')); - } - } - + public function invoke(?object $instance, $args= []) { try { $pass= PHP_VERSION_ID < 80000 && $args ? self::pass($this->reflect, $args) : $args; + $this->reflect->setAccessible(true); return $this->reflect->invokeArgs($instance, $pass); } catch (ReflectionException|ArgumentCountError|TypeError $e) { throw new CannotInvoke($this, $e); diff --git a/src/main/php/lang/reflection/Property.class.php b/src/main/php/lang/reflection/Property.class.php index cd38e94..7fd2a4d 100755 --- a/src/main/php/lang/reflection/Property.class.php +++ b/src/main/php/lang/reflection/Property.class.php @@ -42,25 +42,18 @@ public function constraint() { * Gets this property's value * * @param ?object $instance - * @param ?string|?lang.XPClass|?lang.reflection.Type $context * @return var * @throws lang.reflection.CannotAccess + * @throws lang.reflection.AccessingFailed if getting raises an exception */ - public function get($instance, $context= null) { - - // Only allow reading non-public properties when given a compatible context - if (!$this->reflect->isPublic()) { - if ($context && Reflection::of($context)->is($this->reflect->getDeclaringClass()->name)) { - $this->reflect->setAccessible(true); - } else { - throw new CannotAccess($this, new ReflectionException('Trying to read non-public property')); - } - } - + public function get(?object $instance) { try { + $this->reflect->setAccessible(true); return $this->reflect->getValue($instance); } catch (ReflectionException $e) { throw new CannotAccess($this, $e); + } catch (Throwable $e) { + throw new AccessingFailed($this, $e); } } @@ -69,23 +62,13 @@ public function get($instance, $context= null) { * * @param ?object $instance * @param var $value - * @param ?string|?lang.XPClass|?lang.reflection.Type $context * @return var The given value * @throws lang.reflection.CannotAccess - * @throws lang.reflection.AccessFailed if setting raises an exception + * @throws lang.reflection.AccessingFailed if setting raises an exception */ - public function set($instance, $value, $context= null) { - - // Only allow reading non-public properties when given a compatible context - if (!$this->reflect->isPublic()) { - if ($context && Reflection::of($context)->is($this->reflect->getDeclaringClass()->name)) { - $this->reflect->setAccessible(true); - } else { - throw new CannotAccess($this, new ReflectionException('Trying to write non-public property')); - } - } - + public function set(?object $instance, $value) { try { + $this->reflect->setAccessible(true); $this->reflect->setValue($instance, $value); return $value; } catch (ReflectionException $e) { diff --git a/src/main/php/lang/reflection/Type.class.php b/src/main/php/lang/reflection/Type.class.php index 1f30046..60f97af 100755 --- a/src/main/php/lang/reflection/Type.class.php +++ b/src/main/php/lang/reflection/Type.class.php @@ -162,15 +162,13 @@ public function initializer($function) { return new Initializer($this->reflect); } else if ($function instanceof \Closure) { $reflect= new ReflectionFunction($function); - return new Initializer($this->reflect, $reflect, function($instance, $args, $context) use($function) { + return new Initializer($this->reflect, $reflect, function($instance, $args) use($function) { return $function->call($instance, ...$args); }); } else if ($this->reflect->hasMethod($function)) { $reflect= $this->reflect->getMethod($function); - return new Initializer($this->reflect, $reflect, function($instance, $args, $context) use($reflect) { - if ($context && !$reflect->isPublic() && Reflection::of($context)->isInstance($instance)) { - $reflect->setAccessible(true); - } + return new Initializer($this->reflect, $reflect, function($instance, $args) use($reflect) { + $reflect->setAccessible(true); return $reflect->invokeArgs($instance, $args); }); } diff --git a/src/test/php/lang/reflection/unittest/InstantiationTest.class.php b/src/test/php/lang/reflection/unittest/InstantiationTest.class.php index 7f85691..5c018ee 100755 --- a/src/test/php/lang/reflection/unittest/InstantiationTest.class.php +++ b/src/test/php/lang/reflection/unittest/InstantiationTest.class.php @@ -92,12 +92,6 @@ public function newInstance_cannot_instantiate_using_non_public_constructor($mod $t->newInstance(); } - #[Test, Expect(CannotInstantiate::class), Values(['private', 'protected'])] - public function constructor_cannot_instantiate_using_non_public_constructor($modifier) { - $t= $this->declare('{ '.$modifier.' function __construct() { } }'); - $t->constructor()->newInstance(); - } - #[Test, Values(['private', 'protected'])] public function instantiate_with_non_public_constructor_in_context($modifier) { $t= $this->declare('{ @@ -113,12 +107,6 @@ public function instantiate_with_constructor_promotion() { Assert::equals($this, $t->constructor()->newInstance([$this])->value); } - #[Test, Expect(CannotInstantiate::class)] - public function cannot_instantiate_with_private_constructor_in_incorrect_context() { - $t= $this->declare('{ private function __construct() { } }'); - $t->constructor()->newInstance([], typeof($this)); - } - #[Test, Expect(CannotInstantiate::class)] public function interfaces_cannot_be_instantiated() { Reflection::type(Runnable::class)->newInstance(); diff --git a/src/test/php/lang/reflection/unittest/InvocationTest.class.php b/src/test/php/lang/reflection/unittest/InvocationTest.class.php index 1442b5d..f0a4589 100755 --- a/src/test/php/lang/reflection/unittest/InvocationTest.class.php +++ b/src/test/php/lang/reflection/unittest/InvocationTest.class.php @@ -1,7 +1,7 @@ invoke($this->fixtures[$context]->newInstance(), [])); } - #[Test, Values([['friend'], ['internal']]), Expect(CannotInvoke::class)] - public function cannot_invoke_non_public_method_by_default($method) { - $method= $this->fixtures['parent']->method($method); - $method->invoke($this->fixtures['parent']->newInstance(), []); - } - #[Test, Values([['parent', 'parent'], ['child', 'parent'], ['parent', 'child']])] public function invoke_private_method_in_context($instance, $context) { $method= $this->fixtures['parent']->method('internal'); - Assert::equals('Internal', $method->invoke($this->fixtures[$instance]->newInstance(), [], $this->fixtures[$context])); - } - - #[Test, Expect(CannotInvoke::class)] - public function cannot_invoke_private_method_in_incorrect_context() { - $method= $this->fixtures['parent']->method('internal'); - $method->invoke($this->fixtures['parent']->newInstance(), [], typeof($this)); + Assert::equals('Internal', $method->invoke($this->fixtures[$instance]->newInstance(), [])); } #[Test, Expect(CannotInvoke::class)] @@ -137,11 +125,11 @@ public function invocation_failed_target() { } #[Test] - public function cannot_invoke_target() { - $t= $this->declare('{ private static function fixture() { } }'); + public function cannot_invoke_exceptions_target_member() { + $t= $this->declare('{ private static function fixture($a) { } }'); try { $t->method('fixture')->invoke(null, []); - throw new AssertionFailedError('No exception was raised'); + throw new IllegalStateException('No exception was raised'); } catch (CannotInvoke $expected) { Assert::equals($t->method('fixture'), $expected->target()); } diff --git a/src/test/php/lang/reflection/unittest/PropertiesTest.class.php b/src/test/php/lang/reflection/unittest/PropertiesTest.class.php index bed0279..8576b59 100755 --- a/src/test/php/lang/reflection/unittest/PropertiesTest.class.php +++ b/src/test/php/lang/reflection/unittest/PropertiesTest.class.php @@ -1,9 +1,9 @@ declare('{ private static $fixture = "Test"; }'); - $type->property('fixture')->get(null); - } - - #[Test, Expect(CannotAccess::class)] - public function cannot_write_private_by_default() { - $type= $this->declare('{ private static $fixture = "Test"; }'); - $type->property('fixture')->set(null, 'Modified'); - } - - #[Test, Expect(CannotAccess::class)] - public function cannot_read_private_with_incorrect_context() { - $type= $this->declare('{ private static $fixture = "Test"; }'); - $type->property('fixture')->get(null, typeof($this)); - } - - #[Test, Expect(CannotAccess::class)] - public function cannot_write_private_with_incorrect_context() { - $type= $this->declare('{ private static $fixture = "Test"; }'); - $type->property('fixture')->set(null, 'Modified', typeof($this)); - } - #[Test, Expect(AccessingFailed::class)] public function type_mismatch() { $type= $this->declare('{ private static array $fixture; }'); - $type->property('fixture')->set(null, 1, $type); + $type->property('fixture')->set(null, 1); } #[Test] @@ -114,9 +90,9 @@ public function private_instance_roundtrip() { $type= $this->declare('{ private $fixture = "Test"; }'); $instance= $type->newInstance(); $property= $type->properties()->named('fixture'); - $property->set($instance, 'Modified', $type); + $property->set($instance, 'Modified'); - Assert::equals('Modified', $property->get($instance, $type)); + Assert::equals('Modified', $property->get($instance)); } #[Test] @@ -242,7 +218,7 @@ public function string_representation_with_union_type_declaration() { } #[Test] - public function accessing_failed_target() { + public function set_accessing_failed_exceptions_target_member() { $t= $this->declare('{ public static array $fixture; }'); try { $t->property('fixture')->set(null, 1); @@ -251,15 +227,4 @@ public function accessing_failed_target() { Assert::equals($t->property('fixture'), $expected->target()); } } - - #[Test] - public function cannot_access_target() { - $t= $this->declare('{ private static $fixture; }'); - try { - $t->property('fixture')->get(null); - throw new AssertionFailedError('No exception was raised'); - } catch (CannotAccess $expected) { - Assert::equals($t->property('fixture'), $expected->target()); - } - } } \ No newline at end of file