mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Implement ReflectionProperty::is{Readable,Writable}()
RFC: https://wiki.php.net/rfc/isreadable-iswriteable Fixes GH-15309 Fixes GH-16175 Closes GH-16209
This commit is contained in:
@@ -134,6 +134,8 @@ PHP 8.6 UPGRADE NOTES
|
|||||||
|
|
||||||
- Reflection:
|
- Reflection:
|
||||||
. ReflectionConstant::inNamespace()
|
. ReflectionConstant::inNamespace()
|
||||||
|
. ReflectionProperty::isReadable() ReflectionProperty::isWritable() were
|
||||||
|
added.
|
||||||
|
|
||||||
- Standard:
|
- Standard:
|
||||||
. `clamp()` returns the given value if in range, else return the nearest
|
. `clamp()` returns the given value if in range, else return the nearest
|
||||||
|
|||||||
@@ -6601,6 +6601,242 @@ ZEND_METHOD(ReflectionProperty, isFinal)
|
|||||||
_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
|
_property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static zend_result get_ce_from_scope_name(zend_class_entry **scope, zend_string *scope_name, zend_execute_data *execute_data)
|
||||||
|
{
|
||||||
|
if (!scope_name) {
|
||||||
|
*scope = NULL;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
*scope = zend_lookup_class(scope_name);
|
||||||
|
if (!*scope) {
|
||||||
|
zend_throw_error(NULL, "Class \"%s\" not found", ZSTR_VAL(scope_name));
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_always_inline uint32_t set_visibility_to_visibility(uint32_t set_visibility)
|
||||||
|
{
|
||||||
|
switch (set_visibility) {
|
||||||
|
case ZEND_ACC_PUBLIC_SET:
|
||||||
|
return ZEND_ACC_PUBLIC;
|
||||||
|
case ZEND_ACC_PROTECTED_SET:
|
||||||
|
return ZEND_ACC_PROTECTED;
|
||||||
|
case ZEND_ACC_PRIVATE_SET:
|
||||||
|
return ZEND_ACC_PRIVATE;
|
||||||
|
EMPTY_SWITCH_DEFAULT_CASE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_visibility(uint32_t visibility, zend_class_entry *ce, zend_class_entry *scope)
|
||||||
|
{
|
||||||
|
if (!(visibility & ZEND_ACC_PUBLIC) && (scope != ce)) {
|
||||||
|
if (!scope) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (visibility & ZEND_ACC_PRIVATE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ZEND_ASSERT(visibility & ZEND_ACC_PROTECTED);
|
||||||
|
if (!instanceof_function(scope, ce) && !instanceof_function(ce, scope)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_METHOD(ReflectionProperty, isReadable)
|
||||||
|
{
|
||||||
|
reflection_object *intern;
|
||||||
|
property_reference *ref;
|
||||||
|
zend_string *scope_name;
|
||||||
|
zend_object *obj = NULL;
|
||||||
|
|
||||||
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||||
|
Z_PARAM_STR_OR_NULL(scope_name)
|
||||||
|
Z_PARAM_OPTIONAL
|
||||||
|
Z_PARAM_OBJ_OR_NULL(obj)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
|
||||||
|
GET_REFLECTION_OBJECT_PTR(ref);
|
||||||
|
|
||||||
|
zend_property_info *prop = ref->prop;
|
||||||
|
if (prop && obj) {
|
||||||
|
if (prop->flags & ZEND_ACC_STATIC) {
|
||||||
|
_DO_THROW("null is expected as object argument for static properties");
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
if (!instanceof_function(obj->ce, prop->ce)) {
|
||||||
|
_DO_THROW("Given object is not an instance of the class this property was declared in");
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
prop = reflection_property_get_effective_prop(ref, intern->ce, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_class_entry *ce = obj ? obj->ce : intern->ce;
|
||||||
|
if (!prop) {
|
||||||
|
if (obj && obj->properties && zend_hash_find_ptr(obj->properties, ref->unmangled_name)) {
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
handle_magic_get:
|
||||||
|
if (ce->__get) {
|
||||||
|
if (obj && ce->__isset) {
|
||||||
|
uint32_t *guard = zend_get_property_guard(obj, ref->unmangled_name);
|
||||||
|
if (!((*guard) & ZEND_GUARD_PROPERTY_ISSET)) {
|
||||||
|
GC_ADDREF(obj);
|
||||||
|
*guard |= ZEND_GUARD_PROPERTY_ISSET;
|
||||||
|
zval member;
|
||||||
|
ZVAL_STR(&member, ref->unmangled_name);
|
||||||
|
zend_call_known_instance_method_with_1_params(ce->__isset, obj, return_value, &member);
|
||||||
|
*guard &= ~ZEND_GUARD_PROPERTY_ISSET;
|
||||||
|
OBJ_RELEASE(obj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
if (obj && zend_lazy_object_must_init(obj)) {
|
||||||
|
obj = zend_lazy_object_init(obj);
|
||||||
|
if (!obj) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
if (obj->properties && zend_hash_find_ptr(obj->properties, ref->unmangled_name)) {
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_class_entry *scope;
|
||||||
|
if (get_ce_from_scope_name(&scope, scope_name, execute_data) == FAILURE) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_visibility(prop->flags & ZEND_ACC_PPP_MASK, prop->ce, scope)) {
|
||||||
|
if (!(prop->flags & ZEND_ACC_STATIC)) {
|
||||||
|
goto handle_magic_get;
|
||||||
|
}
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop->flags & ZEND_ACC_VIRTUAL) {
|
||||||
|
ZEND_ASSERT(prop->hooks);
|
||||||
|
if (!prop->hooks[ZEND_PROPERTY_HOOK_GET]) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
} else if (obj && (!prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET])) {
|
||||||
|
retry_declared:;
|
||||||
|
zval *prop_val = OBJ_PROP(obj, prop->offset);
|
||||||
|
if (Z_TYPE_P(prop_val) == IS_UNDEF) {
|
||||||
|
if (zend_lazy_object_must_init(obj) && (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY)) {
|
||||||
|
obj = zend_lazy_object_init(obj);
|
||||||
|
if (!obj) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
goto retry_declared;
|
||||||
|
}
|
||||||
|
if (!(Z_PROP_FLAG_P(prop_val) & IS_PROP_UNINIT)) {
|
||||||
|
goto handle_magic_get;
|
||||||
|
}
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
} else if (prop->flags & ZEND_ACC_STATIC) {
|
||||||
|
if (ce->default_static_members_count && !CE_STATIC_MEMBERS(ce)) {
|
||||||
|
zend_class_init_statics(ce);
|
||||||
|
}
|
||||||
|
zval *prop_val = CE_STATIC_MEMBERS(ce) + prop->offset;
|
||||||
|
RETURN_BOOL(!Z_ISUNDEF_P(prop_val));
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_METHOD(ReflectionProperty, isWritable)
|
||||||
|
{
|
||||||
|
reflection_object *intern;
|
||||||
|
property_reference *ref;
|
||||||
|
zend_string *scope_name;
|
||||||
|
zend_object *obj = NULL;
|
||||||
|
|
||||||
|
ZEND_PARSE_PARAMETERS_START(1, 2)
|
||||||
|
Z_PARAM_STR_OR_NULL(scope_name)
|
||||||
|
Z_PARAM_OPTIONAL
|
||||||
|
Z_PARAM_OBJ_OR_NULL(obj)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
|
||||||
|
GET_REFLECTION_OBJECT_PTR(ref);
|
||||||
|
|
||||||
|
zend_property_info *prop = ref->prop;
|
||||||
|
if (prop && obj) {
|
||||||
|
if (prop->flags & ZEND_ACC_STATIC) {
|
||||||
|
_DO_THROW("null is expected as object argument for static properties");
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
if (!instanceof_function(obj->ce, prop->ce)) {
|
||||||
|
_DO_THROW("Given object is not an instance of the class this property was declared in");
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
prop = reflection_property_get_effective_prop(ref, intern->ce, obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_class_entry *ce = obj ? obj->ce : intern->ce;
|
||||||
|
if (!prop) {
|
||||||
|
if (!(ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
/* This path is effectively unreachable, but theoretically possible for
|
||||||
|
* two internal classes where ZEND_ACC_NO_DYNAMIC_PROPERTIES is only
|
||||||
|
* added to the subclass, in which case a ReflectionProperty can be
|
||||||
|
* constructed on the parent class, and then tested on the subclass. */
|
||||||
|
handle_magic_set:
|
||||||
|
RETURN_BOOL(ce->__set);
|
||||||
|
}
|
||||||
|
|
||||||
|
zend_class_entry *scope;
|
||||||
|
if (get_ce_from_scope_name(&scope, scope_name, execute_data) == FAILURE) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_visibility(prop->flags & ZEND_ACC_PPP_MASK, prop->ce, scope)) {
|
||||||
|
if (!(prop->flags & ZEND_ACC_STATIC)) {
|
||||||
|
goto handle_magic_set;
|
||||||
|
}
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
uint32_t set_visibility = prop->flags & ZEND_ACC_PPP_SET_MASK;
|
||||||
|
if (!set_visibility) {
|
||||||
|
set_visibility = zend_visibility_to_set_visibility(prop->flags & ZEND_ACC_PPP_MASK);
|
||||||
|
}
|
||||||
|
if (!check_visibility(set_visibility_to_visibility(set_visibility), prop->ce, scope)) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop->flags & ZEND_ACC_VIRTUAL) {
|
||||||
|
ZEND_ASSERT(prop->hooks);
|
||||||
|
if (!prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
} else if (obj && (prop->flags & ZEND_ACC_READONLY)) {
|
||||||
|
retry:;
|
||||||
|
zval *prop_val = OBJ_PROP(obj, prop->offset);
|
||||||
|
if (Z_TYPE_P(prop_val) == IS_UNDEF
|
||||||
|
&& zend_lazy_object_must_init(obj)
|
||||||
|
&& (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY)) {
|
||||||
|
obj = zend_lazy_object_init(obj);
|
||||||
|
if (!obj) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
if (Z_TYPE_P(prop_val) != IS_UNDEF && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_REINITABLE)) {
|
||||||
|
RETURN_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* {{{ Constructor. Throws an Exception in case the given extension does not exist */
|
/* {{{ Constructor. Throws an Exception in case the given extension does not exist */
|
||||||
ZEND_METHOD(ReflectionExtension, __construct)
|
ZEND_METHOD(ReflectionExtension, __construct)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -574,6 +574,10 @@ class ReflectionProperty implements Reflector
|
|||||||
public function getHook(PropertyHookType $type): ?ReflectionMethod {}
|
public function getHook(PropertyHookType $type): ?ReflectionMethod {}
|
||||||
|
|
||||||
public function isFinal(): bool {}
|
public function isFinal(): bool {}
|
||||||
|
|
||||||
|
public function isReadable(?string $scope, ?object $object = null): bool {}
|
||||||
|
|
||||||
|
public function isWritable(?string $scope, ?object $object = null): bool {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @not-serializable */
|
/** @not-serializable */
|
||||||
|
|||||||
13
ext/reflection/php_reflection_arginfo.h
generated
13
ext/reflection/php_reflection_arginfo.h
generated
@@ -1,5 +1,5 @@
|
|||||||
/* This is a generated file, edit php_reflection.stub.php instead.
|
/* This is a generated file, edit php_reflection.stub.php instead.
|
||||||
* Stub hash: b09497083efa7035dab6047f6d845ceaec81579e
|
* Stub hash: 267472e2b726ca5e788eb5cc3e946bc9aa7c9c41
|
||||||
* Has decl header: yes */
|
* Has decl header: yes */
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0)
|
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Reflection_getModifierNames, 0, 1, IS_ARRAY, 0)
|
||||||
@@ -473,6 +473,13 @@ ZEND_END_ARG_INFO()
|
|||||||
|
|
||||||
#define arginfo_class_ReflectionProperty_isFinal arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType
|
#define arginfo_class_ReflectionProperty_isFinal arginfo_class_ReflectionFunctionAbstract_hasTentativeReturnType
|
||||||
|
|
||||||
|
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_ReflectionProperty_isReadable, 0, 1, _IS_BOOL, 0)
|
||||||
|
ZEND_ARG_TYPE_INFO(0, scope, IS_STRING, 1)
|
||||||
|
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, object, IS_OBJECT, 1, "null")
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
|
#define arginfo_class_ReflectionProperty_isWritable arginfo_class_ReflectionProperty_isReadable
|
||||||
|
|
||||||
#define arginfo_class_ReflectionClassConstant___clone arginfo_class_ReflectionFunctionAbstract___clone
|
#define arginfo_class_ReflectionClassConstant___clone arginfo_class_ReflectionFunctionAbstract___clone
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionClassConstant___construct, 0, 0, 2)
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ReflectionClassConstant___construct, 0, 0, 2)
|
||||||
@@ -894,6 +901,8 @@ ZEND_METHOD(ReflectionProperty, getHooks);
|
|||||||
ZEND_METHOD(ReflectionProperty, hasHook);
|
ZEND_METHOD(ReflectionProperty, hasHook);
|
||||||
ZEND_METHOD(ReflectionProperty, getHook);
|
ZEND_METHOD(ReflectionProperty, getHook);
|
||||||
ZEND_METHOD(ReflectionProperty, isFinal);
|
ZEND_METHOD(ReflectionProperty, isFinal);
|
||||||
|
ZEND_METHOD(ReflectionProperty, isReadable);
|
||||||
|
ZEND_METHOD(ReflectionProperty, isWritable);
|
||||||
ZEND_METHOD(ReflectionClassConstant, __construct);
|
ZEND_METHOD(ReflectionClassConstant, __construct);
|
||||||
ZEND_METHOD(ReflectionClassConstant, __toString);
|
ZEND_METHOD(ReflectionClassConstant, __toString);
|
||||||
ZEND_METHOD(ReflectionClassConstant, getName);
|
ZEND_METHOD(ReflectionClassConstant, getName);
|
||||||
@@ -1198,6 +1207,8 @@ static const zend_function_entry class_ReflectionProperty_methods[] = {
|
|||||||
ZEND_ME(ReflectionProperty, hasHook, arginfo_class_ReflectionProperty_hasHook, ZEND_ACC_PUBLIC)
|
ZEND_ME(ReflectionProperty, hasHook, arginfo_class_ReflectionProperty_hasHook, ZEND_ACC_PUBLIC)
|
||||||
ZEND_ME(ReflectionProperty, getHook, arginfo_class_ReflectionProperty_getHook, ZEND_ACC_PUBLIC)
|
ZEND_ME(ReflectionProperty, getHook, arginfo_class_ReflectionProperty_getHook, ZEND_ACC_PUBLIC)
|
||||||
ZEND_ME(ReflectionProperty, isFinal, arginfo_class_ReflectionProperty_isFinal, ZEND_ACC_PUBLIC)
|
ZEND_ME(ReflectionProperty, isFinal, arginfo_class_ReflectionProperty_isFinal, ZEND_ACC_PUBLIC)
|
||||||
|
ZEND_ME(ReflectionProperty, isReadable, arginfo_class_ReflectionProperty_isReadable, ZEND_ACC_PUBLIC)
|
||||||
|
ZEND_ME(ReflectionProperty, isWritable, arginfo_class_ReflectionProperty_isWritable, ZEND_ACC_PUBLIC)
|
||||||
ZEND_FE_END
|
ZEND_FE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
8
ext/reflection/php_reflection_decl.h
generated
8
ext/reflection/php_reflection_decl.h
generated
@@ -1,12 +1,12 @@
|
|||||||
/* This is a generated file, edit php_reflection.stub.php instead.
|
/* This is a generated file, edit php_reflection.stub.php instead.
|
||||||
* Stub hash: b09497083efa7035dab6047f6d845ceaec81579e */
|
* Stub hash: 267472e2b726ca5e788eb5cc3e946bc9aa7c9c41 */
|
||||||
|
|
||||||
#ifndef ZEND_PHP_REFLECTION_DECL_b09497083efa7035dab6047f6d845ceaec81579e_H
|
#ifndef ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H
|
||||||
#define ZEND_PHP_REFLECTION_DECL_b09497083efa7035dab6047f6d845ceaec81579e_H
|
#define ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H
|
||||||
|
|
||||||
typedef enum zend_enum_PropertyHookType {
|
typedef enum zend_enum_PropertyHookType {
|
||||||
ZEND_ENUM_PropertyHookType_Get = 1,
|
ZEND_ENUM_PropertyHookType_Get = 1,
|
||||||
ZEND_ENUM_PropertyHookType_Set = 2,
|
ZEND_ENUM_PropertyHookType_Set = 2,
|
||||||
} zend_enum_PropertyHookType;
|
} zend_enum_PropertyHookType;
|
||||||
|
|
||||||
#endif /* ZEND_PHP_REFLECTION_DECL_b09497083efa7035dab6047f6d845ceaec81579e_H */
|
#endif /* ZEND_PHP_REFLECTION_DECL_267472e2b726ca5e788eb5cc3e946bc9aa7c9c41_H */
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() dynamic
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
|
class A {}
|
||||||
|
|
||||||
|
$a = new A;
|
||||||
|
|
||||||
|
$a->a = 'a';
|
||||||
|
$r = new ReflectionProperty($a, 'a');
|
||||||
|
|
||||||
|
var_dump($r->isReadable(null, $a));
|
||||||
|
unset($a->a);
|
||||||
|
var_dump($r->isReadable(null, $a));
|
||||||
|
|
||||||
|
$a = new A;
|
||||||
|
var_dump($r->isReadable(null, $a));
|
||||||
|
|
||||||
|
var_dump($r->isReadable(null, null));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() hooks
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public $a { get => $this->a; }
|
||||||
|
public $b { get => 42; }
|
||||||
|
public $c { set => $value; }
|
||||||
|
public $d { set {} }
|
||||||
|
public $e { get => $this->e; set => $value; }
|
||||||
|
public $f { get {} set {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
function test($scope) {
|
||||||
|
$rc = new ReflectionClass(A::class);
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from ' . ($scope ?? 'global') . ': ';
|
||||||
|
var_dump($rp->isReadable($scope, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('A');
|
||||||
|
test(null);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
a from A: bool(true)
|
||||||
|
b from A: bool(true)
|
||||||
|
c from A: bool(true)
|
||||||
|
d from A: bool(false)
|
||||||
|
e from A: bool(true)
|
||||||
|
f from A: bool(true)
|
||||||
|
a from global: bool(true)
|
||||||
|
b from global: bool(true)
|
||||||
|
c from global: bool(true)
|
||||||
|
d from global: bool(false)
|
||||||
|
e from global: bool(true)
|
||||||
|
f from global: bool(true)
|
||||||
72
ext/reflection/tests/ReflectionProperty_isReadable_init.phpt
Normal file
72
ext/reflection/tests/ReflectionProperty_isReadable_init.phpt
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() init
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public $a;
|
||||||
|
public int $b;
|
||||||
|
public int $c = 42;
|
||||||
|
public int $d;
|
||||||
|
public int $e;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
unset($this->e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class B {
|
||||||
|
public int $f;
|
||||||
|
public int $g;
|
||||||
|
public int $h;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
unset($this->g);
|
||||||
|
unset($this->h);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($name) {
|
||||||
|
return $name === 'h';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C {
|
||||||
|
public int $i;
|
||||||
|
public int $j;
|
||||||
|
public int $k;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
unset($this->j);
|
||||||
|
unset($this->k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test($class) {
|
||||||
|
$rc = new ReflectionClass($class);
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from global: ';
|
||||||
|
var_dump($rp->isReadable(null, new $class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('A');
|
||||||
|
test('B');
|
||||||
|
test('C');
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
a from global: bool(true)
|
||||||
|
b from global: bool(false)
|
||||||
|
c from global: bool(true)
|
||||||
|
d from global: bool(false)
|
||||||
|
e from global: bool(false)
|
||||||
|
f from global: bool(false)
|
||||||
|
g from global: bool(false)
|
||||||
|
h from global: bool(true)
|
||||||
|
i from global: bool(false)
|
||||||
|
j from global: bool(true)
|
||||||
|
k from global: bool(true)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() invalid scope
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public $prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = new ReflectionProperty('A', 'prop');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$r->isReadable('B', null);
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e::class, ': ', $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Error: Class "B" not found
|
||||||
29
ext/reflection/tests/ReflectionProperty_isReadable_lazy.phpt
Normal file
29
ext/reflection/tests/ReflectionProperty_isReadable_lazy.phpt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() lazy
|
||||||
|
--CREDITS--
|
||||||
|
Arnaud Le Blanc (arnaud-lb)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public int $a;
|
||||||
|
public int $b;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new ReflectionClass(A::class);
|
||||||
|
$obj = $rc->newLazyProxy(fn() => new A());
|
||||||
|
|
||||||
|
$rp = new ReflectionProperty(A::class, 'a');
|
||||||
|
var_dump($rp->isReadable(null, $obj));
|
||||||
|
|
||||||
|
$rp = new ReflectionProperty(A::class, 'b');
|
||||||
|
var_dump($rp->isReadable(null, $obj));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
|
bool(false)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() lazy dynamic
|
||||||
|
--CREDITS--
|
||||||
|
Arnaud Le Blanc (arnaud-lb)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
|
class A {
|
||||||
|
public $_;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->prop = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new ReflectionClass(A::class);
|
||||||
|
$obj = $rc->newLazyProxy(fn() => new A());
|
||||||
|
|
||||||
|
$rp = new ReflectionProperty(new A, 'prop');
|
||||||
|
var_dump($rp->isReadable(null, $obj));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(true)
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() lazy isset
|
||||||
|
--CREDITS--
|
||||||
|
Arnaud Le Blanc (arnaud-lb)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
|
class A {
|
||||||
|
public $_;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->prop = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __get($name) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new ReflectionClass(A::class);
|
||||||
|
$obj = $rc->newLazyProxy(fn() => new A);
|
||||||
|
|
||||||
|
$rp = new ReflectionProperty(new A, 'prop');
|
||||||
|
var_dump($rp->isReadable(null, $obj));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() static
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public static $a;
|
||||||
|
public static int $b;
|
||||||
|
public static int $c = 42;
|
||||||
|
protected static int $d = 42;
|
||||||
|
private static int $e = 42;
|
||||||
|
public private(set) static int $f = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = new ReflectionProperty('A', 'a');
|
||||||
|
try {
|
||||||
|
$r->isReadable(null, new A);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e::class, ': ', $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new ReflectionClass('A');
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from global: ';
|
||||||
|
var_dump($rp->isReadable(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ReflectionException: null is expected as object argument for static properties
|
||||||
|
a from global: bool(true)
|
||||||
|
b from global: bool(false)
|
||||||
|
c from global: bool(true)
|
||||||
|
d from global: bool(false)
|
||||||
|
e from global: bool(false)
|
||||||
|
f from global: bool(true)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() unrelated object
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
public $prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends B {}
|
||||||
|
|
||||||
|
class D {}
|
||||||
|
|
||||||
|
function test($obj) {
|
||||||
|
$r = new ReflectionProperty('B', 'prop');
|
||||||
|
try {
|
||||||
|
var_dump($r->isReadable(null, $obj));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e::class, ': ', $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test(new A);
|
||||||
|
test(new B);
|
||||||
|
test(new C);
|
||||||
|
test(new D);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ReflectionException: Given object is not an instance of the class this property was declared in
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
ReflectionException: Given object is not an instance of the class this property was declared in
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isReadable() visibility
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
public $a;
|
||||||
|
protected $b;
|
||||||
|
private $c;
|
||||||
|
public protected(set) int $d = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends B {}
|
||||||
|
|
||||||
|
class D extends C {
|
||||||
|
public function __get($name) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
class E extends D {
|
||||||
|
private $f;
|
||||||
|
|
||||||
|
public function __isset($name) {
|
||||||
|
return $name === 'f';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test($scope) {
|
||||||
|
$rc = new ReflectionClass(B::class);
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from ' . ($scope ?? 'global') . ': ';
|
||||||
|
var_dump($rp->isReadable($scope, $scope && $scope !== 'A' ? new $scope : null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (['A', 'B', 'C', 'D', 'E'] as $scope) {
|
||||||
|
test($scope);
|
||||||
|
}
|
||||||
|
test(null);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
a from A: bool(true)
|
||||||
|
b from A: bool(true)
|
||||||
|
c from A: bool(false)
|
||||||
|
d from A: bool(true)
|
||||||
|
a from B: bool(true)
|
||||||
|
b from B: bool(true)
|
||||||
|
c from B: bool(true)
|
||||||
|
d from B: bool(true)
|
||||||
|
a from C: bool(true)
|
||||||
|
b from C: bool(true)
|
||||||
|
c from C: bool(false)
|
||||||
|
d from C: bool(true)
|
||||||
|
a from D: bool(true)
|
||||||
|
b from D: bool(true)
|
||||||
|
c from D: bool(true)
|
||||||
|
d from D: bool(true)
|
||||||
|
a from E: bool(true)
|
||||||
|
b from E: bool(true)
|
||||||
|
c from E: bool(false)
|
||||||
|
d from E: bool(true)
|
||||||
|
a from global: bool(true)
|
||||||
|
b from global: bool(false)
|
||||||
|
c from global: bool(false)
|
||||||
|
d from global: bool(true)
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() dynamic
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
|
class A {
|
||||||
|
private $a;
|
||||||
|
}
|
||||||
|
|
||||||
|
$a = new A;
|
||||||
|
|
||||||
|
$r = new ReflectionProperty($a, 'a');
|
||||||
|
var_dump($r->isWritable(null, $a));
|
||||||
|
var_dump($r->isWritable(null, null));
|
||||||
|
|
||||||
|
$a->b = 'b';
|
||||||
|
$r = new ReflectionProperty($a, 'b');
|
||||||
|
var_dump($r->isWritable(null, $a));
|
||||||
|
|
||||||
|
$a = new A;
|
||||||
|
var_dump($r->isWritable(null, $a));
|
||||||
|
|
||||||
|
var_dump($r->isWritable(null, null));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() visibility
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public $a { get => $this->a; }
|
||||||
|
public $b { get => 42; }
|
||||||
|
public $c { set => $value; }
|
||||||
|
public $d { set {} }
|
||||||
|
public $e { get => $this->e; set => $value; }
|
||||||
|
public $f { get {} set {} }
|
||||||
|
}
|
||||||
|
|
||||||
|
function test($scope) {
|
||||||
|
$rc = new ReflectionClass(A::class);
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from ' . ($scope ?? 'global') . ': ';
|
||||||
|
var_dump($rp->isWritable($scope, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('A');
|
||||||
|
test(null);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
a from A: bool(true)
|
||||||
|
b from A: bool(false)
|
||||||
|
c from A: bool(true)
|
||||||
|
d from A: bool(true)
|
||||||
|
e from A: bool(true)
|
||||||
|
f from A: bool(true)
|
||||||
|
a from global: bool(true)
|
||||||
|
b from global: bool(false)
|
||||||
|
c from global: bool(true)
|
||||||
|
d from global: bool(true)
|
||||||
|
e from global: bool(true)
|
||||||
|
f from global: bool(true)
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() invalid scope
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public $prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = new ReflectionProperty('A', 'prop');
|
||||||
|
|
||||||
|
try {
|
||||||
|
$r->isWritable('B', null);
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e::class, ': ', $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Error: Class "B" not found
|
||||||
29
ext/reflection/tests/ReflectionProperty_isWritable_lazy.phpt
Normal file
29
ext/reflection/tests/ReflectionProperty_isWritable_lazy.phpt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() lazy
|
||||||
|
--CREDITS--
|
||||||
|
Arnaud Le Blanc (arnaud-lb)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public public(set) readonly int $a;
|
||||||
|
public public(set) readonly int $b;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->a = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new ReflectionClass(A::class);
|
||||||
|
$obj = $rc->newLazyProxy(fn() => new A());
|
||||||
|
|
||||||
|
$rp = new ReflectionProperty(A::class, 'a');
|
||||||
|
var_dump($rp->isWritable(null, $obj));
|
||||||
|
|
||||||
|
$rp = new ReflectionProperty(A::class, 'b');
|
||||||
|
var_dump($rp->isWritable(null, $obj));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
bool(false)
|
||||||
|
bool(true)
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() readonly
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public readonly int $a;
|
||||||
|
public readonly int $b;
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->a = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __clone() {
|
||||||
|
test($this);
|
||||||
|
$this->a = 43;
|
||||||
|
test($this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test($instance) {
|
||||||
|
$rc = new ReflectionClass($instance);
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from A: ';
|
||||||
|
var_dump($rp->isWritable($instance::class, $instance));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test(new A);
|
||||||
|
clone new A;
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
a from A: bool(false)
|
||||||
|
b from A: bool(true)
|
||||||
|
a from A: bool(true)
|
||||||
|
b from A: bool(true)
|
||||||
|
a from A: bool(false)
|
||||||
|
b from A: bool(true)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() static
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
public static $a;
|
||||||
|
public static int $b;
|
||||||
|
public static int $c = 42;
|
||||||
|
protected static int $d = 42;
|
||||||
|
private static int $e = 42;
|
||||||
|
public private(set) static int $f = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
$r = new ReflectionProperty('A', 'a');
|
||||||
|
try {
|
||||||
|
$r->isWritable(null, new A);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e::class, ': ', $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$rc = new ReflectionClass('A');
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from global: ';
|
||||||
|
var_dump($rp->isWritable(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ReflectionException: null is expected as object argument for static properties
|
||||||
|
a from global: bool(true)
|
||||||
|
b from global: bool(true)
|
||||||
|
c from global: bool(true)
|
||||||
|
d from global: bool(false)
|
||||||
|
e from global: bool(false)
|
||||||
|
f from global: bool(false)
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() unrelated object
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {
|
||||||
|
}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
public $prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends B {}
|
||||||
|
|
||||||
|
class D {}
|
||||||
|
|
||||||
|
function test($obj) {
|
||||||
|
$r = new ReflectionProperty('B', 'prop');
|
||||||
|
try {
|
||||||
|
var_dump($r->isWritable(null, $obj));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e::class, ': ', $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test(new A);
|
||||||
|
test(new B);
|
||||||
|
test(new C);
|
||||||
|
test(new D);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
ReflectionException: Given object is not an instance of the class this property was declared in
|
||||||
|
bool(true)
|
||||||
|
bool(true)
|
||||||
|
ReflectionException: Given object is not an instance of the class this property was declared in
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
--TEST--
|
||||||
|
Test ReflectionProperty::isWritable() visibility
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class A {}
|
||||||
|
|
||||||
|
class B extends A {
|
||||||
|
public $a;
|
||||||
|
protected $b;
|
||||||
|
private $c;
|
||||||
|
public private(set) int $d;
|
||||||
|
public protected(set) int $e;
|
||||||
|
public readonly int $f;
|
||||||
|
}
|
||||||
|
|
||||||
|
class C extends B {}
|
||||||
|
|
||||||
|
class D extends C {
|
||||||
|
public function __set($name, $value) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function test($scope) {
|
||||||
|
$rc = new ReflectionClass(B::class);
|
||||||
|
foreach ($rc->getProperties() as $rp) {
|
||||||
|
echo $rp->getName() . ' from ' . ($scope ?? 'global') . ': ';
|
||||||
|
var_dump($rp->isWritable($scope, $scope && $scope !== 'A' ? new $scope : null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('A');
|
||||||
|
test('B');
|
||||||
|
test('C');
|
||||||
|
test('D');
|
||||||
|
test(null);
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
a from A: bool(true)
|
||||||
|
b from A: bool(true)
|
||||||
|
c from A: bool(false)
|
||||||
|
d from A: bool(false)
|
||||||
|
e from A: bool(true)
|
||||||
|
f from A: bool(true)
|
||||||
|
a from B: bool(true)
|
||||||
|
b from B: bool(true)
|
||||||
|
c from B: bool(true)
|
||||||
|
d from B: bool(true)
|
||||||
|
e from B: bool(true)
|
||||||
|
f from B: bool(true)
|
||||||
|
a from C: bool(true)
|
||||||
|
b from C: bool(true)
|
||||||
|
c from C: bool(false)
|
||||||
|
d from C: bool(false)
|
||||||
|
e from C: bool(true)
|
||||||
|
f from C: bool(true)
|
||||||
|
a from D: bool(true)
|
||||||
|
b from D: bool(true)
|
||||||
|
c from D: bool(true)
|
||||||
|
d from D: bool(false)
|
||||||
|
e from D: bool(true)
|
||||||
|
f from D: bool(true)
|
||||||
|
a from global: bool(true)
|
||||||
|
b from global: bool(false)
|
||||||
|
c from global: bool(false)
|
||||||
|
d from global: bool(false)
|
||||||
|
e from global: bool(false)
|
||||||
|
f from global: bool(false)
|
||||||
Reference in New Issue
Block a user