Skip to content

Commit c73f94f

Browse files
committed
Raise exceptions when reading or writing non-public properties
Fixes behavior change introduced in PHP 8.1, see https://wiki.php.net/rfc/make-reflection-setaccessible-no-op
1 parent 5620f8d commit c73f94f

File tree

2 files changed

+19
-10
lines changed

2 files changed

+19
-10
lines changed

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ XP Reflection ChangeLog
55

66
## 1.6.0 / 2021-08-03
77

8+
* Fixed `Method::invoke()`, `Property::get()` and `Property::set()` not
9+
raising exceptions in PHP 8.1, an incompatibility created by the RFC
10+
https://wiki.php.net/rfc/make-reflection-setaccessible-no-op
11+
(@thekid)
812
* Fixed warnings in PHP 8.1 about `getIterator()` compatibility, see
913
https://wiki.php.net/rfc/internal_method_return_types
1014
(@thekid)

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

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

3+
use ReflectionException, ReflectionUnionType, Throwable;
34
use lang\{Reflection, XPClass, Type, TypeUnion};
45

56
/**
@@ -45,16 +46,18 @@ public function constraint() {
4546
*/
4647
public function get($instance, $context= null) {
4748

48-
// Success oriented: Let PHP's reflection API raise the exceptions for us
49-
if ($context && !$this->reflect->isPublic()) {
50-
if (Reflection::of($context)->is($this->reflect->class)) {
49+
// Only allow reading non-public properties when given a compatible context
50+
if (!$this->reflect->isPublic()) {
51+
if ($context && Reflection::of($context)->is($this->reflect->class)) {
5152
$this->reflect->setAccessible(true);
53+
} else {
54+
throw new CannotAccess($this, new ReflectionException('Trying to read non-public property'));
5255
}
5356
}
5457

5558
try {
5659
return $this->reflect->getValue($instance);
57-
} catch (\ReflectionException $e) {
60+
} catch (ReflectionException $e) {
5861
throw new CannotAccess($this, $e);
5962
}
6063
}
@@ -71,19 +74,21 @@ public function get($instance, $context= null) {
7174
*/
7275
public function set($instance, $value, $context= null) {
7376

74-
// Success oriented: Let PHP's reflection API raise the exceptions for us
75-
if ($context && !$this->reflect->isPublic()) {
76-
if (Reflection::of($context)->is($this->reflect->class)) {
77+
// Only allow reading non-public properties when given a compatible context
78+
if (!$this->reflect->isPublic()) {
79+
if ($context && Reflection::of($context)->is($this->reflect->class)) {
7780
$this->reflect->setAccessible(true);
81+
} else {
82+
throw new CannotAccess($this, new ReflectionException('Trying to write non-public property'));
7883
}
7984
}
8085

8186
try {
8287
$this->reflect->setValue($instance, $value);
8388
return $value;
84-
} catch (\ReflectionException $e) {
89+
} catch (ReflectionException $e) {
8590
throw new CannotAccess($this, $e);
86-
} catch (\Throwable $e) {
91+
} catch (Throwable $e) {
8792
throw new AccessingFailed($this, $e);
8893
}
8994
}
@@ -95,7 +100,7 @@ public function toString() {
95100
$t= PHP_VERSION_ID >= 70400 ? $this->reflect->getType() : null;
96101
if (null === $t) {
97102
$name= Reflection::meta()->propertyType($this->reflect) ?? 'var';
98-
} else if ($t instanceof \ReflectionUnionType) {
103+
} else if ($t instanceof ReflectionUnionType) {
99104
$name= '';
100105
foreach ($t->getTypes() as $component) {
101106
$name.= '|'.$component->getName();

0 commit comments

Comments
 (0)