From 86b883808fa08ba9f7d3344ad8ee60886062fa0c Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Wed, 29 Jul 2026 10:37:14 +0200 Subject: [PATCH 1/2] Reapply reading properties of objects that implement \ArrayAccess Restores https://github.com/webonyx/graphql-php/pull/1531, reverted in v15.37.1 because it exposed internal object state as field values. Also removes the regression test added by the revert, which pinned the behavior this change undoes. --- src/Utils/Utils.php | 8 +++- tests/Executor/ExecutorTest.php | 76 +++------------------------------ 2 files changed, 12 insertions(+), 72 deletions(-) diff --git a/src/Utils/Utils.php b/src/Utils/Utils.php index 73b7a9f04..cbffe2588 100644 --- a/src/Utils/Utils.php +++ b/src/Utils/Utils.php @@ -268,10 +268,16 @@ public static function suggestionList(string $input, array $options): array */ public static function extractKey($objectLikeValue, string $key) { - if (is_array($objectLikeValue) || $objectLikeValue instanceof \ArrayAccess) { + if (is_array($objectLikeValue)) { return $objectLikeValue[$key] ?? null; } + if ($objectLikeValue instanceof \ArrayAccess) { + return $objectLikeValue[$key] + ?? $objectLikeValue->{$key} // @phpstan-ignore-line Variable property access on ArrayAccess is fine here, we do the same for arbitrary objects + ?? null; + } + if (is_object($objectLikeValue)) { return $objectLikeValue->{$key} ?? null; } diff --git a/tests/Executor/ExecutorTest.php b/tests/Executor/ExecutorTest.php index f59eb7cb5..065356e96 100644 --- a/tests/Executor/ExecutorTest.php +++ b/tests/Executor/ExecutorTest.php @@ -1190,6 +1190,7 @@ public function testDefaultResolverGrabsValuesOffOfCommonPhpDataStructures(): vo 'name' => 'ArrayAccess', 'fields' => [ 'set' => Type::int(), + 'setProperty' => Type::int(), 'unsetNull' => Type::int(), 'unsetThrow' => Type::int(), ], @@ -1224,6 +1225,8 @@ public function testDefaultResolverGrabsValuesOffOfCommonPhpDataStructures(): vo 'arrayAccess' => [ 'type' => $ArrayAccess, 'resolve' => static fn (): \ArrayAccess => new class implements \ArrayAccess { + public ?int $setProperty = 1; + /** @param mixed $offset */ #[\ReturnTypeWillChange] public function offsetExists($offset): bool @@ -1317,6 +1320,7 @@ public function __get(string $name): ?int } arrayAccess { set + setProperty unsetNull unsetThrow } @@ -1344,6 +1348,7 @@ public function __get(string $name): ?int ], 'arrayAccess' => [ 'set' => 1, + 'setProperty' => 1, 'unsetNull' => null, 'unsetThrow' => null, ], @@ -1362,75 +1367,4 @@ public function __get(string $name): ?int $result->toArray() ); } - - public function testDefaultResolverDoesNotAccessPropertiesOfArrayAccess(): void - { - $schema = new Schema([ - 'query' => new ObjectType([ - 'name' => 'Query', - 'fields' => [ - 'arrayAccess' => [ - 'type' => new ObjectType([ - 'name' => 'ArrayAccess', - 'fields' => [ - 'property' => Type::int(), - ], - ]), - // Eloquent models implement \ArrayAccess to expose their attributes. - // Their properties hold internal state that must stay hidden. - // https://github.com/webonyx/graphql-php/pull/1531 - 'resolve' => static fn (): \ArrayAccess => new class implements \ArrayAccess { - public ?int $property = 1; - - /** @param mixed $offset */ - #[\ReturnTypeWillChange] - public function offsetExists($offset): bool - { - return false; - } - - /** @param mixed $offset */ - #[\ReturnTypeWillChange] - public function offsetGet($offset): ?int - { - return null; - } - - /** - * @param mixed $offset - * @param mixed $value - */ - #[\ReturnTypeWillChange] - public function offsetSet($offset, $value): void {} - - /** @param mixed $offset */ - #[\ReturnTypeWillChange] - public function offsetUnset($offset): void {} - }, - ], - ], - ]), - ]); - - $query = Parser::parse(' - { - arrayAccess { - property - } - } - '); - - $result = Executor::execute($schema, $query); - - self::assertSame( - [ - 'data' => [ - 'arrayAccess' => [ - 'property' => null, - ], - ], - ], - $result->toArray() - ); - } } From 8674466520b1cfcc3d4a95e7e44aab4f080aebb1 Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Wed, 29 Jul 2026 10:38:28 +0200 Subject: [PATCH 2/2] Add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 940edd760..ea6ee0f4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ You can find and compare releases at the [GitHub release page](https://github.co ## Unreleased +### Added + +- If an object implements `\ArrayAccess`, check both array value and property https://github.com/webonyx/graphql-php/pull/1960 + ## v15.37.1 ### Fixed