From 380e9d31fa5af8c09f27f092fcd64073c757efa2 Mon Sep 17 00:00:00 2001 From: Mahmud Bello Date: Sat, 14 Mar 2026 21:09:08 +0100 Subject: [PATCH 01/11] fix : Improve performance by disabling return/resolved values validation --- src/Executor/ExecutionContext.php | 6 +- src/Executor/Executor.php | 13 ++- src/Executor/ReferenceExecutor.php | 70 ++++++++------- src/GraphQL.php | 13 ++- src/Server/Helper.php | 3 +- src/Server/ServerConfig.php | 18 ++++ tests/Executor/TrustResultTest.php | 135 +++++++++++++++++++++++++++++ 7 files changed, 218 insertions(+), 40 deletions(-) create mode 100644 tests/Executor/TrustResultTest.php diff --git a/src/Executor/ExecutionContext.php b/src/Executor/ExecutionContext.php index 4450b61d3..99867e3d3 100644 --- a/src/Executor/ExecutionContext.php +++ b/src/Executor/ExecutionContext.php @@ -54,6 +54,8 @@ class ExecutionContext public PromiseAdapter $promiseAdapter; + public bool $trustResult; + /** * @param array $fragments * @param mixed $rootValue @@ -73,7 +75,8 @@ public function __construct( array $errors, callable $fieldResolver, callable $argsMapper, - PromiseAdapter $promiseAdapter + PromiseAdapter $promiseAdapter, + bool $trustResult = false ) { $this->schema = $schema; $this->fragments = $fragments; @@ -85,6 +88,7 @@ public function __construct( $this->fieldResolver = $fieldResolver; $this->argsMapper = $argsMapper; $this->promiseAdapter = $promiseAdapter; + $this->trustResult = $trustResult; } public function addError(Error $error): void diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index f7ce2bff1..2c76c645b 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -18,7 +18,7 @@ * * @phpstan-type ArgsMapper callable(array, FieldDefinition, FieldNode, mixed): mixed * @phpstan-type FieldResolver callable(mixed, array, mixed, ResolveInfo): mixed - * @phpstan-type ImplementationFactory callable(PromiseAdapter, Schema, DocumentNode, mixed, mixed, array, ?string, callable, callable): ExecutorImplementation + * @phpstan-type ImplementationFactory callable(PromiseAdapter, Schema, DocumentNode, mixed, mixed, array, ?string, callable, ?callable, bool): ExecutorImplementation * * @see \GraphQL\Tests\Executor\ExecutorTest */ @@ -125,7 +125,8 @@ public static function execute( $contextValue = null, ?array $variableValues = null, ?string $operationName = null, - ?callable $fieldResolver = null + ?callable $fieldResolver = null, + bool $trustResult = false ): ExecutionResult { $promiseAdapter = new SyncPromiseAdapter(); @@ -137,7 +138,9 @@ public static function execute( $contextValue, $variableValues, $operationName, - $fieldResolver + $fieldResolver, + null, + $trustResult ); return $promiseAdapter->wait($result); @@ -167,7 +170,8 @@ public static function promiseToExecute( ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, - ?callable $argsMapper = null + ?callable $argsMapper = null, + bool $trustResult = false ): Promise { $executor = (self::$implementationFactory)( $promiseAdapter, @@ -179,6 +183,7 @@ public static function promiseToExecute( $operationName, $fieldResolver ?? self::$defaultFieldResolver, $argsMapper ?? self::$defaultArgsMapper, + $trustResult, ); return $executor->doExecute(); diff --git a/src/Executor/ReferenceExecutor.php b/src/Executor/ReferenceExecutor.php index 53c52dd8a..f8ce50c5b 100644 --- a/src/Executor/ReferenceExecutor.php +++ b/src/Executor/ReferenceExecutor.php @@ -105,7 +105,8 @@ public static function create( array $variableValues, ?string $operationName, callable $fieldResolver, - ?callable $argsMapper = null // TODO make non-optional in next major release + ?callable $argsMapper = null, // TODO make non-optional in next major release + bool $trustResult = false ): ExecutorImplementation { $exeContext = static::buildExecutionContext( $schema, @@ -117,6 +118,7 @@ public static function create( $fieldResolver, $argsMapper ?? Executor::getDefaultArgsMapper(), $promiseAdapter, + $trustResult ); if (is_array($exeContext)) { @@ -152,7 +154,8 @@ protected static function buildExecutionContext( ?string $operationName, callable $fieldResolver, callable $argsMapper, - PromiseAdapter $promiseAdapter + PromiseAdapter $promiseAdapter, + bool $trustResult = false ) { /** @var list $errors */ $errors = []; @@ -229,7 +232,8 @@ protected static function buildExecutionContext( $errors, $fieldResolver, $argsMapper, - $promiseAdapter + $promiseAdapter, + $trustResult ); } @@ -884,7 +888,7 @@ protected function completeValue( $result, $contextValue ); - if ($completed === null) { + if ($completed === null && ! $this->exeContext->trustResult) { throw new InvariantViolation("Cannot return null for non-nullable field \"{$info->parentType}.{$info->fieldName}\"."); } @@ -897,7 +901,7 @@ protected function completeValue( // If field type is List, complete each item in the list with the inner type if ($returnType instanceof ListOfType) { - if (! is_iterable($result)) { + if (! $this->exeContext->trustResult && ! is_iterable($result)) { $resultType = gettype($result); throw new InvariantViolation("Expected field {$info->parentType}.{$info->fieldName} to return iterable, but got: {$resultType}."); @@ -1047,6 +1051,10 @@ protected function completeListValue( */ protected function completeLeafValue(LeafType $returnType, $result) { + if ($this->exeContext->trustResult) { + return $result; + } + try { return $returnType->serialize($result); } catch (\Throwable $error) { @@ -1219,36 +1227,38 @@ protected function completeObjectValue( // If there is an isTypeOf predicate function, call it with the // current result. If isTypeOf returns false, then raise an error rather // than continuing execution. - $isTypeOf = $returnType->isTypeOf($result, $contextValue, $info); - if ($isTypeOf !== null) { - $promise = $this->getPromise($isTypeOf); - if ($promise !== null) { - return $promise->then(function ($isTypeOfResult) use ( - $contextValue, - $returnType, - $fieldNodes, - $path, - $unaliasedPath, - $result - ) { - if (! $isTypeOfResult) { - throw $this->invalidReturnTypeError($returnType, $result, $fieldNodes); - } - - return $this->collectAndExecuteSubfields( + if (! $this->exeContext->trustResult) { + $isTypeOf = $returnType->isTypeOf($result, $contextValue, $info); + if ($isTypeOf !== null) { + $promise = $this->getPromise($isTypeOf); + if ($promise !== null) { + return $promise->then(function ($isTypeOfResult) use ( + $contextValue, $returnType, $fieldNodes, $path, $unaliasedPath, - $result, - $contextValue - ); - }); - } + $result + ) { + if (! $isTypeOfResult) { + throw $this->invalidReturnTypeError($returnType, $result, $fieldNodes); + } - assert(is_bool($isTypeOf), 'Promise would return early'); - if (! $isTypeOf) { - throw $this->invalidReturnTypeError($returnType, $result, $fieldNodes); + return $this->collectAndExecuteSubfields( + $returnType, + $fieldNodes, + $path, + $unaliasedPath, + $result, + $contextValue + ); + }); + } + + assert(is_bool($isTypeOf), 'Promise would return early'); + if (! $isTypeOf) { + throw $this->invalidReturnTypeError($returnType, $result, $fieldNodes); + } } } diff --git a/src/GraphQL.php b/src/GraphQL.php index 919b09dec..40e0f0819 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -90,7 +90,8 @@ public static function executeQuery( ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, - ?array $validationRules = null + ?array $validationRules = null, + bool $trustResult = false ): ExecutionResult { $promiseAdapter = new SyncPromiseAdapter(); @@ -103,7 +104,8 @@ public static function executeQuery( $variableValues, $operationName, $fieldResolver, - $validationRules + $validationRules, + $trustResult ); return $promiseAdapter->wait($promise); @@ -132,7 +134,8 @@ public static function promiseToExecute( ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, - ?array $validationRules = null + ?array $validationRules = null, + bool $trustResult = false ): Promise { try { $documentNode = $source instanceof DocumentNode @@ -168,7 +171,9 @@ public static function promiseToExecute( $context, $variableValues, $operationName, - $fieldResolver + $fieldResolver, + null, + $trustResult ); } catch (Error $e) { return $promiseAdapter->createFulfilled( diff --git a/src/Server/Helper.php b/src/Server/Helper.php index c77e3af61..5485e3e5c 100644 --- a/src/Server/Helper.php +++ b/src/Server/Helper.php @@ -299,7 +299,8 @@ protected function promiseToExecuteOperation( $op->variables, $op->operation, $config->getFieldResolver(), - $this->resolveValidationRules($config, $op, $doc, $operationType) + $this->resolveValidationRules($config, $op, $doc, $operationType), + $config->getTrustResult() ); } catch (RequestError $e) { $result = $promiseAdapter->createFulfilled( diff --git a/src/Server/ServerConfig.php b/src/Server/ServerConfig.php index 08d7517ee..f7e8d7485 100644 --- a/src/Server/ServerConfig.php +++ b/src/Server/ServerConfig.php @@ -85,6 +85,9 @@ public static function create(array $config = []): self case 'promiseAdapter': $instance->setPromiseAdapter($value); break; + case 'trustResult': + $instance->setTrustResult($value); + break; default: throw new InvariantViolation("Unknown server config option: {$key}"); } @@ -135,6 +138,8 @@ public static function create(array $config = []): self private ?PromiseAdapter $promiseAdapter = null; + private bool $trustResult = false; + /** * @var callable|null * @@ -276,6 +281,14 @@ public function setPromiseAdapter(PromiseAdapter $promiseAdapter): self return $this; } + /** @api */ + public function setTrustResult(bool $trustResult): self + { + $this->trustResult = $trustResult; + + return $this; + } + /** @return mixed|callable */ public function getContext() { @@ -344,4 +357,9 @@ public function getQueryBatching(): bool { return $this->queryBatching; } + + public function getTrustResult(): bool + { + return $this->trustResult; + } } diff --git a/tests/Executor/TrustResultTest.php b/tests/Executor/TrustResultTest.php new file mode 100644 index 000000000..13747ae4d --- /dev/null +++ b/tests/Executor/TrustResultTest.php @@ -0,0 +1,135 @@ + new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'list' => [ + 'type' => Type::listOf(Type::string()), + 'resolve' => static fn (): string => 'not an iterable', + ], + ], + ]), + ]); + + $query = '{ list }'; + + // Without trustResult, it should have an error in the result + $result = Executor::execute($schema, Parser::parse($query)); + $this->assertCount(1, $result->errors); + $this->assertStringContainsString('Expected field Query.list to return iterable, but got: string.', $result->errors[0]->getMessage()); + + // With trustResult, it should NOT have the InvariantViolation error. + // However, it will fail with a TypeError because of the 'iterable' type hint in completeListValue. + $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); + $this->assertCount(1, $result->errors); + $this->assertStringContainsString('completeListValue()', $result->errors[0]->getMessage()); + $this->assertStringContainsString('must be of type', $result->errors[0]->getMessage()); + } + + public function testTrustResultSkipsLeafSerialization(): void + { + $schema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'scalar' => [ + 'type' => Type::int(), + 'resolve' => static fn (): string => '123', // should be int, but we trust it + ], + ], + ]), + ]); + + $query = '{ scalar }'; + + // Without trustResult, it returns 123 (int) because Type::int() serializes '123' to 123 + $result = Executor::execute($schema, Parser::parse($query)); + $this->assertSame(123, $result->data['scalar']); + + // With trustResult, it should return '123' (string) directly without serialization + $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); + $this->assertSame('123', $result->data['scalar']); + } + + public function testTrustResultSkipsIsTypeOfValidation(): void + { + $someType = new ObjectType([ + 'name' => 'SomeType', + 'fields' => [ + 'foo' => [ + 'type' => Type::string(), + 'resolve' => static fn ($root) => $root['foo'] ?? null, + ], + ], + 'isTypeOf' => static fn ($value): bool => is_array($value) && isset($value['valid']) && $value['valid'] === true, + ]); + + $schema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'obj' => [ + 'type' => $someType, + 'resolve' => static fn (): array => ['foo' => 'bar', 'valid' => false], + ], + ], + ]), + ]); + + $query = '{ obj { foo } }'; + + // Without trustResult, it should have an error + $result = Executor::execute($schema, Parser::parse($query)); + $this->assertCount(1, $result->errors); + $this->assertStringContainsString('Expected value of type "SomeType" but got:', $result->errors[0]->getMessage()); + + // With trustResult, it should skip isTypeOf check + $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); + $this->assertCount(0, $result->errors); + $this->assertSame('bar', $result->data['obj']['foo']); + } + + public function testTrustResultSkipsNonNullValidation(): void + { + $schema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'nonNull' => [ + 'type' => Type::nonNull(Type::string()), + 'resolve' => static fn (): ?string => null, + ], + ], + ]), + ]); + + $query = '{ nonNull }'; + + // Without trustResult, it should have an error + $result = Executor::execute($schema, Parser::parse($query)); + $this->assertCount(1, $result->errors); + $this->assertStringContainsString('Cannot return null for non-nullable field "Query.nonNull".', $result->errors[0]->getMessage()); + + // With trustResult, it returns null without error + $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); + $this->assertCount(0, $result->errors); + $this->assertNull($result->data['nonNull']); + } +} From 23df4952a7945b3cc3ad0d2c934923a266c9cb8b Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2026 20:31:12 +0000 Subject: [PATCH 02/11] Autofix --- docs/class-reference.md | 14 +++++++++----- tests/Executor/TrustResultTest.php | 4 +--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/class-reference.md b/docs/class-reference.md index f6e627c43..ee756f3b9 100644 --- a/docs/class-reference.md +++ b/docs/class-reference.md @@ -72,7 +72,8 @@ static function executeQuery( ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, - ?array $validationRules = null + ?array $validationRules = null, + bool $trustResult = false ): GraphQL\Executor\ExecutionResult ``` @@ -100,7 +101,8 @@ static function promiseToExecute( ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, - ?array $validationRules = null + ?array $validationRules = null, + bool $trustResult = false ): GraphQL\Executor\Promise\Promise ``` @@ -1590,7 +1592,7 @@ Implements the "Evaluating requests" section of the GraphQL specification. ```php @phpstan-type ArgsMapper callable(array, FieldDefinition, FieldNode, mixed): mixed @phpstan-type FieldResolver callable(mixed, array, mixed, ResolveInfo): mixed -@phpstan-type ImplementationFactory callable(PromiseAdapter, Schema, DocumentNode, mixed, mixed, array, ?string, callable, callable): ExecutorImplementation +@phpstan-type ImplementationFactory callable(PromiseAdapter, Schema, DocumentNode, mixed, mixed, array, ?string, callable, ?callable, bool): ExecutorImplementation ``` @see \GraphQL\Tests\Executor\ExecutorTest @@ -1621,7 +1623,8 @@ static function execute( $contextValue = null, ?array $variableValues = null, ?string $operationName = null, - ?callable $fieldResolver = null + ?callable $fieldResolver = null, + bool $trustResult = false ): GraphQL\Executor\ExecutionResult ``` @@ -1650,7 +1653,8 @@ static function promiseToExecute( ?array $variableValues = null, ?string $operationName = null, ?callable $fieldResolver = null, - ?callable $argsMapper = null + ?callable $argsMapper = null, + bool $trustResult = false ): GraphQL\Executor\Promise\Promise ``` diff --git a/tests/Executor/TrustResultTest.php b/tests/Executor/TrustResultTest.php index 13747ae4d..7394883d3 100644 --- a/tests/Executor/TrustResultTest.php +++ b/tests/Executor/TrustResultTest.php @@ -11,9 +11,7 @@ final class TrustResultTest extends TestCase { - /** - * @see https://github.com/webonyx/graphql-php/issues/1493 - */ + /** @see https://github.com/webonyx/graphql-php/issues/1493 */ public function testTrustResultSkipsListIterableValidation(): void { $schema = new Schema([ From cd80ee52f0c71249dcbc815eeaf269cf08e47d2d Mon Sep 17 00:00:00 2001 From: Mahmud Bello <75342173+mahmudsudo@users.noreply.github.com> Date: Sat, 14 Mar 2026 21:43:22 +0100 Subject: [PATCH 03/11] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/GraphQL.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/GraphQL.php b/src/GraphQL.php index e7c4b211e..27039567c 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -120,6 +120,11 @@ public static function executeQuery( * @param mixed $context * @param array|null $variableValues * @param array|null $validationRules Defaults to using all available rules + * @param bool $trustResult When true, assumes resolver results are already correctly typed + * and serialized and skips normal type and serialization checks. + * This is unsafe for untrusted schemas or inputs and should only + * be enabled when you fully control the schema, resolvers and + * execution pipeline. * * @api * From bfd3409abb6d7ab5cb428f98a010358637fd2e3b Mon Sep 17 00:00:00 2001 From: Mahmud Bello Date: Sat, 14 Mar 2026 22:04:42 +0100 Subject: [PATCH 04/11] fix : ci errors and copilot additions --- src/Executor/Executor.php | 18 +++++++++++++-- src/Executor/ReferenceExecutor.php | 2 +- src/GraphQL.php | 6 +++++ tests/Executor/TrustResultTest.php | 37 ++++++++++++++++-------------- tests/GraphQLTest.php | 26 +++++++++++++++++++++ 5 files changed, 69 insertions(+), 20 deletions(-) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index 2c76c645b..c82eaac06 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -173,7 +173,8 @@ public static function promiseToExecute( ?callable $argsMapper = null, bool $trustResult = false ): Promise { - $executor = (self::$implementationFactory)( + $factory = self::$implementationFactory; + $args = [ $promiseAdapter, $schema, $documentNode, @@ -184,7 +185,20 @@ public static function promiseToExecute( $fieldResolver ?? self::$defaultFieldResolver, $argsMapper ?? self::$defaultArgsMapper, $trustResult, - ); + ]; + + try { + // Check if userland factory supports the 10th argument for BC + $reflector = new \ReflectionFunction(\Closure::fromCallable($factory)); + if ($reflector->getNumberOfParameters() < 10) { + // Remove $trustResult argument for older implementations + array_pop($args); + } + } catch (\ReflectionException $e) { + // Fallback for safety, should not happen for valid callables + } + + $executor = $factory(...$args); return $executor->doExecute(); } diff --git a/src/Executor/ReferenceExecutor.php b/src/Executor/ReferenceExecutor.php index b3eaaa4cd..e3a2b8d0f 100644 --- a/src/Executor/ReferenceExecutor.php +++ b/src/Executor/ReferenceExecutor.php @@ -901,7 +901,7 @@ protected function completeValue( // If field type is List, complete each item in the list with the inner type if ($returnType instanceof ListOfType) { - if (! $this->exeContext->trustResult && ! is_iterable($result)) { + if (! is_iterable($result)) { $resultType = gettype($result); throw new InvariantViolation("Expected field {$info->parentType}.{$info->fieldName} to return iterable, but got: {$resultType}."); diff --git a/src/GraphQL.php b/src/GraphQL.php index 27039567c..369979dbe 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -70,12 +70,18 @@ class GraphQL * A set of rules for query validation step. Default value is all available rules. * Empty array would allow to skip query validation (may be convenient for persisted * queries which are validated before persisting and assumed valid during execution) + * trustResult: + * When true, assumes resolver results are already correctly typed and serialized + * and skips normal type and serialization checks. This is unsafe for untrusted + * schemas or inputs and should only be enabled when you fully control the schema, + * resolvers and execution pipeline. * * @param string|DocumentNode $source * @param mixed $rootValue * @param mixed $contextValue * @param array|null $variableValues * @param array|null $validationRules + * @param bool $trustResult * * @api * diff --git a/tests/Executor/TrustResultTest.php b/tests/Executor/TrustResultTest.php index 7394883d3..9cc48ee3d 100644 --- a/tests/Executor/TrustResultTest.php +++ b/tests/Executor/TrustResultTest.php @@ -30,15 +30,13 @@ public function testTrustResultSkipsListIterableValidation(): void // Without trustResult, it should have an error in the result $result = Executor::execute($schema, Parser::parse($query)); - $this->assertCount(1, $result->errors); - $this->assertStringContainsString('Expected field Query.list to return iterable, but got: string.', $result->errors[0]->getMessage()); + self::assertCount(1, $result->errors); + self::assertStringContainsString('Expected field Query.list to return iterable, but got: string.', $result->errors[0]->getMessage()); - // With trustResult, it should NOT have the InvariantViolation error. - // However, it will fail with a TypeError because of the 'iterable' type hint in completeListValue. + // With trustResult, it should NOT skip the InvariantViolation error since it's required for type safety $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); - $this->assertCount(1, $result->errors); - $this->assertStringContainsString('completeListValue()', $result->errors[0]->getMessage()); - $this->assertStringContainsString('must be of type', $result->errors[0]->getMessage()); + self::assertCount(1, $result->errors); + self::assertStringContainsString('Expected field Query.list to return iterable, but got: string.', $result->errors[0]->getMessage()); } public function testTrustResultSkipsLeafSerialization(): void @@ -59,11 +57,13 @@ public function testTrustResultSkipsLeafSerialization(): void // Without trustResult, it returns 123 (int) because Type::int() serializes '123' to 123 $result = Executor::execute($schema, Parser::parse($query)); - $this->assertSame(123, $result->data['scalar']); + self::assertIsArray($result->data); + self::assertSame(123, $result->data['scalar']); // With trustResult, it should return '123' (string) directly without serialization $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); - $this->assertSame('123', $result->data['scalar']); + self::assertIsArray($result->data); + self::assertSame('123', $result->data['scalar']); } public function testTrustResultSkipsIsTypeOfValidation(): void @@ -95,13 +95,15 @@ public function testTrustResultSkipsIsTypeOfValidation(): void // Without trustResult, it should have an error $result = Executor::execute($schema, Parser::parse($query)); - $this->assertCount(1, $result->errors); - $this->assertStringContainsString('Expected value of type "SomeType" but got:', $result->errors[0]->getMessage()); + self::assertCount(1, $result->errors); + self::assertStringContainsString('Expected value of type "SomeType" but got:', $result->errors[0]->getMessage()); // With trustResult, it should skip isTypeOf check $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); - $this->assertCount(0, $result->errors); - $this->assertSame('bar', $result->data['obj']['foo']); + self::assertCount(0, $result->errors); + self::assertIsArray($result->data); + self::assertIsArray($result->data['obj']); + self::assertSame('bar', $result->data['obj']['foo']); } public function testTrustResultSkipsNonNullValidation(): void @@ -122,12 +124,13 @@ public function testTrustResultSkipsNonNullValidation(): void // Without trustResult, it should have an error $result = Executor::execute($schema, Parser::parse($query)); - $this->assertCount(1, $result->errors); - $this->assertStringContainsString('Cannot return null for non-nullable field "Query.nonNull".', $result->errors[0]->getMessage()); + self::assertCount(1, $result->errors); + self::assertStringContainsString('Cannot return null for non-nullable field "Query.nonNull".', $result->errors[0]->getMessage()); // With trustResult, it returns null without error $result = Executor::execute($schema, Parser::parse($query), null, null, null, null, null, true); - $this->assertCount(0, $result->errors); - $this->assertNull($result->data['nonNull']); + self::assertCount(0, $result->errors); + self::assertIsArray($result->data); + self::assertNull($result->data['nonNull']); } } diff --git a/tests/GraphQLTest.php b/tests/GraphQLTest.php index 04c869f99..54dc700a7 100644 --- a/tests/GraphQLTest.php +++ b/tests/GraphQLTest.php @@ -38,4 +38,30 @@ public function testPromiseToExecute(): void $result = $promiseAdapter->wait($promise); self::assertSame(['data' => ['sayHi' => 'Hi John!']], $result->toArray()); } + + public function testTrustResultFlagPropagatesViaExecuteQuery(): void + { + $schema = new Schema( + (new SchemaConfig()) + ->setQuery(new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'scalarNumber' => [ + 'type' => Type::int(), + 'resolve' => static fn (): string => '123', // should be int, but we trust it + ], + ], + ])) + ); + + $query = '{ scalarNumber }'; + + // Without trustResult, it returns 123 (int) because Type::int() serializes '123' to 123 + $result = GraphQL::executeQuery($schema, $query); + self::assertSame(['data' => ['scalarNumber' => 123]], $result->toArray()); + + // With trustResult, it should return '123' (string) directly without serialization + $result = GraphQL::executeQuery($schema, $query, null, null, null, null, null, null, true); + self::assertSame(['data' => ['scalarNumber' => '123']], $result->toArray()); + } } From 93c530c2ba0905e9da7a6222a73225e07f88185a Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 14 Mar 2026 21:12:16 +0000 Subject: [PATCH 05/11] Autofix --- docs/class-reference.md | 10 ++++++++++ src/GraphQL.php | 1 - 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/class-reference.md b/docs/class-reference.md index ee756f3b9..b48179021 100644 --- a/docs/class-reference.md +++ b/docs/class-reference.md @@ -52,6 +52,11 @@ See [related documentation](executing-queries.md). * A set of rules for query validation step. Default value is all available rules. * Empty array would allow to skip query validation (may be convenient for persisted * queries which are validated before persisting and assumed valid during execution) + * trustResult: + * When true, assumes resolver results are already correctly typed and serialized + * and skips normal type and serialization checks. This is unsafe for untrusted + * schemas or inputs and should only be enabled when you fully control the schema, + * resolvers and execution pipeline. * * @param string|DocumentNode $source * @param mixed $rootValue @@ -87,6 +92,11 @@ static function executeQuery( * @param mixed $context * @param array|null $variableValues * @param array|null $validationRules Defaults to using all available rules + * @param bool $trustResult When true, assumes resolver results are already correctly typed + * and serialized and skips normal type and serialization checks. + * This is unsafe for untrusted schemas or inputs and should only + * be enabled when you fully control the schema, resolvers and + * execution pipeline. * * @api * diff --git a/src/GraphQL.php b/src/GraphQL.php index 369979dbe..93e8815a9 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -81,7 +81,6 @@ class GraphQL * @param mixed $contextValue * @param array|null $variableValues * @param array|null $validationRules - * @param bool $trustResult * * @api * From 2e8c43d7ff343c8f20bd6e0695ffec4aa5dbaac0 Mon Sep 17 00:00:00 2001 From: Mahmud Bello Date: Sat, 14 Mar 2026 22:27:26 +0100 Subject: [PATCH 06/11] fix : ci errors and copilot additions --- src/Executor/Executor.php | 1 + src/GraphQL.php | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index c82eaac06..01ff378c7 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -198,6 +198,7 @@ public static function promiseToExecute( // Fallback for safety, should not happen for valid callables } + // @phpstan-ignore arguments.count $executor = $factory(...$args); return $executor->doExecute(); diff --git a/src/GraphQL.php b/src/GraphQL.php index 369979dbe..93e8815a9 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -81,7 +81,6 @@ class GraphQL * @param mixed $contextValue * @param array|null $variableValues * @param array|null $validationRules - * @param bool $trustResult * * @api * From b583dc1d7af6eebad73fe9f38446f2e0895c9a65 Mon Sep 17 00:00:00 2001 From: Mahmud Bello Date: Sun, 15 Mar 2026 04:28:20 +0100 Subject: [PATCH 07/11] additional corrections added --- src/Executor/Executor.php | 12 ------- src/GraphQL.php | 15 +++++---- tests/Executor/ExecutorTest.php | 55 +++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index 01ff378c7..53a113faf 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -187,18 +187,6 @@ public static function promiseToExecute( $trustResult, ]; - try { - // Check if userland factory supports the 10th argument for BC - $reflector = new \ReflectionFunction(\Closure::fromCallable($factory)); - if ($reflector->getNumberOfParameters() < 10) { - // Remove $trustResult argument for older implementations - array_pop($args); - } - } catch (\ReflectionException $e) { - // Fallback for safety, should not happen for valid callables - } - - // @phpstan-ignore arguments.count $executor = $factory(...$args); return $executor->doExecute(); diff --git a/src/GraphQL.php b/src/GraphQL.php index 93e8815a9..4e3336557 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -72,9 +72,11 @@ class GraphQL * queries which are validated before persisting and assumed valid during execution) * trustResult: * When true, assumes resolver results are already correctly typed and serialized - * and skips normal type and serialization checks. This is unsafe for untrusted - * schemas or inputs and should only be enabled when you fully control the schema, - * resolvers and execution pipeline. + * and skips normal type and serialization checks. This is purely for + * performance optimization. The tradeoff is potentially corrupted results for the client + * if resolvers return malformed data. Only enable this when you are confident + * that your resolvers are safely and correctly returning data conforming to + * the schema. * * @param string|DocumentNode $source * @param mixed $rootValue @@ -127,9 +129,10 @@ public static function executeQuery( * @param array|null $validationRules Defaults to using all available rules * @param bool $trustResult When true, assumes resolver results are already correctly typed * and serialized and skips normal type and serialization checks. - * This is unsafe for untrusted schemas or inputs and should only - * be enabled when you fully control the schema, resolvers and - * execution pipeline. + * This is purely for performance optimization. The tradeoff is + * potentially corrupted results for the client if resolvers return + * malformed data. Only enable this when you are confident that + * your resolvers correctly return data conforming to the schema. * * @api * diff --git a/tests/Executor/ExecutorTest.php b/tests/Executor/ExecutorTest.php index 812c33d4a..e4db0c5ba 100644 --- a/tests/Executor/ExecutorTest.php +++ b/tests/Executor/ExecutorTest.php @@ -1362,4 +1362,59 @@ public function __get(string $name): ?int $result->toArray() ); } + + public function testCustomImplementationFactoryIgnoresExtraArguments(): void + { + $called = false; + + // This factory takes only 9 arguments, representing older userland implementations + // that do not typehint or expect the 10th `$trustResult` argument. + Executor::setImplementationFactory( + static function ( + $promiseAdapter, + $schema, + $documentNode, + $rootValue, + $contextValue, + $variableValues, + $operationName, + $fieldResolver, + $argsMapper + ) use (&$called) { + $called = true; + return \GraphQL\Executor\ReferenceExecutor::create( + $promiseAdapter, + $schema, + $documentNode, + $rootValue, + $contextValue, + $variableValues, + $operationName, + $fieldResolver, + $argsMapper, + false + ); + } + ); + + $doc = '{ a }'; + $data = ['a' => 'b']; + $ast = Parser::parse($doc); + $schema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Type', + 'fields' => [ + 'a' => ['type' => Type::string()], + ], + ]), + ]); + + $ex = Executor::execute($schema, $ast, $data); + + self::assertTrue($called); + self::assertSame(['data' => ['a' => 'b']], $ex->toArray()); + + // Reset the factory + Executor::setImplementationFactory([\GraphQL\Executor\ReferenceExecutor::class, 'create']); + } } From 78c1946ba47d077f819b44560cb29d9edbaa972a Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:18:05 +0000 Subject: [PATCH 08/11] Autofix --- docs/class-reference.md | 15 +++++++++------ src/GraphQL.php | 6 +++--- tests/Executor/ExecutorTest.php | 7 ++++--- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/docs/class-reference.md b/docs/class-reference.md index b48179021..88db5b8a9 100644 --- a/docs/class-reference.md +++ b/docs/class-reference.md @@ -54,9 +54,11 @@ See [related documentation](executing-queries.md). * queries which are validated before persisting and assumed valid during execution) * trustResult: * When true, assumes resolver results are already correctly typed and serialized - * and skips normal type and serialization checks. This is unsafe for untrusted - * schemas or inputs and should only be enabled when you fully control the schema, - * resolvers and execution pipeline. + * and skips normal type and serialization checks. This is purely for + * performance optimization. The tradeoff is potentially corrupted results for the client + * if resolvers return malformed data. Only enable this when you are confident + * that your resolvers are safely and correctly returning data conforming to + * the schema. * * @param string|DocumentNode $source * @param mixed $rootValue @@ -94,9 +96,10 @@ static function executeQuery( * @param array|null $validationRules Defaults to using all available rules * @param bool $trustResult When true, assumes resolver results are already correctly typed * and serialized and skips normal type and serialization checks. - * This is unsafe for untrusted schemas or inputs and should only - * be enabled when you fully control the schema, resolvers and - * execution pipeline. + * This is purely for performance optimization. The tradeoff is + * potentially corrupted results for the client if resolvers return + * malformed data. Only enable this when you are confident that + * your resolvers correctly return data conforming to the schema. * * @api * diff --git a/src/GraphQL.php b/src/GraphQL.php index 4e3336557..08f51a8b1 100644 --- a/src/GraphQL.php +++ b/src/GraphQL.php @@ -129,9 +129,9 @@ public static function executeQuery( * @param array|null $validationRules Defaults to using all available rules * @param bool $trustResult When true, assumes resolver results are already correctly typed * and serialized and skips normal type and serialization checks. - * This is purely for performance optimization. The tradeoff is - * potentially corrupted results for the client if resolvers return - * malformed data. Only enable this when you are confident that + * This is purely for performance optimization. The tradeoff is + * potentially corrupted results for the client if resolvers return + * malformed data. Only enable this when you are confident that * your resolvers correctly return data conforming to the schema. * * @api diff --git a/tests/Executor/ExecutorTest.php b/tests/Executor/ExecutorTest.php index e4db0c5ba..0f16ab784 100644 --- a/tests/Executor/ExecutorTest.php +++ b/tests/Executor/ExecutorTest.php @@ -1366,7 +1366,7 @@ public function __get(string $name): ?int public function testCustomImplementationFactoryIgnoresExtraArguments(): void { $called = false; - + // This factory takes only 9 arguments, representing older userland implementations // that do not typehint or expect the 10th `$trustResult` argument. Executor::setImplementationFactory( @@ -1382,6 +1382,7 @@ static function ( $argsMapper ) use (&$called) { $called = true; + return \GraphQL\Executor\ReferenceExecutor::create( $promiseAdapter, $schema, @@ -1410,10 +1411,10 @@ static function ( ]); $ex = Executor::execute($schema, $ast, $data); - + self::assertTrue($called); self::assertSame(['data' => ['a' => 'b']], $ex->toArray()); - + // Reset the factory Executor::setImplementationFactory([\GraphQL\Executor\ReferenceExecutor::class, 'create']); } From f77b399c3cb519733ed56542f697291a4c218fea Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Sun, 15 Mar 2026 10:29:48 +0100 Subject: [PATCH 09/11] Simplify ImplementationFactory test --- src/Executor/Executor.php | 7 ++----- tests/Executor/ExecutorTest.php | 37 ++++++++++++++++----------------- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index 53a113faf..2c76c645b 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -173,8 +173,7 @@ public static function promiseToExecute( ?callable $argsMapper = null, bool $trustResult = false ): Promise { - $factory = self::$implementationFactory; - $args = [ + $executor = (self::$implementationFactory)( $promiseAdapter, $schema, $documentNode, @@ -185,9 +184,7 @@ public static function promiseToExecute( $fieldResolver ?? self::$defaultFieldResolver, $argsMapper ?? self::$defaultArgsMapper, $trustResult, - ]; - - $executor = $factory(...$args); + ); return $executor->doExecute(); } diff --git a/tests/Executor/ExecutorTest.php b/tests/Executor/ExecutorTest.php index 0f16ab784..219b6575f 100644 --- a/tests/Executor/ExecutorTest.php +++ b/tests/Executor/ExecutorTest.php @@ -8,6 +8,9 @@ use GraphQL\Error\FormattedError; use GraphQL\Error\UserError; use GraphQL\Executor\Executor; +use GraphQL\Executor\Promise\PromiseAdapter; +use GraphQL\Executor\ReferenceExecutor; +use GraphQL\Language\AST\DocumentNode; use GraphQL\Language\AST\OperationDefinitionNode; use GraphQL\Language\Parser; use GraphQL\Tests\Executor\TestClasses\NotSpecial; @@ -30,6 +33,9 @@ final class ExecutorTest extends TestCase public function tearDown(): void { Executor::setDefaultPromiseAdapter(); + Executor::setImplementationFactory([ReferenceExecutor::class, 'create']); + + parent::tearDown(); } // Execute: Handles basic execution tasks @@ -1367,23 +1373,21 @@ public function testCustomImplementationFactoryIgnoresExtraArguments(): void { $called = false; - // This factory takes only 9 arguments, representing older userland implementations - // that do not typehint or expect the 10th `$trustResult` argument. Executor::setImplementationFactory( + // Represents older userland implementations that don't know newly added args static function ( - $promiseAdapter, - $schema, - $documentNode, + PromiseAdapter $promiseAdapter, + Schema $schema, + DocumentNode $documentNode, $rootValue, $contextValue, - $variableValues, - $operationName, - $fieldResolver, - $argsMapper + array $variableValues, + ?string $operationName, + callable $fieldResolver ) use (&$called) { $called = true; - return \GraphQL\Executor\ReferenceExecutor::create( + return ReferenceExecutor::create( $promiseAdapter, $schema, $documentNode, @@ -1391,9 +1395,7 @@ static function ( $contextValue, $variableValues, $operationName, - $fieldResolver, - $argsMapper, - false + $fieldResolver ); } ); @@ -1405,17 +1407,14 @@ static function ( 'query' => new ObjectType([ 'name' => 'Type', 'fields' => [ - 'a' => ['type' => Type::string()], + 'a' => Type::string(), ], ]), ]); - $ex = Executor::execute($schema, $ast, $data); + $executor = Executor::execute($schema, $ast, $data); self::assertTrue($called); - self::assertSame(['data' => ['a' => 'b']], $ex->toArray()); - - // Reset the factory - Executor::setImplementationFactory([\GraphQL\Executor\ReferenceExecutor::class, 'create']); + self::assertSame(['data' => $data], $executor->toArray()); } } From e49fc6f5b5d797acb0d42f131f2ff093ee93d43a Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Sun, 15 Mar 2026 10:50:36 +0100 Subject: [PATCH 10/11] add benchmark --- benchmarks/TrustResultBench.php | 294 ++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 benchmarks/TrustResultBench.php diff --git a/benchmarks/TrustResultBench.php b/benchmarks/TrustResultBench.php new file mode 100644 index 000000000..9e9c3c53e --- /dev/null +++ b/benchmarks/TrustResultBench.php @@ -0,0 +1,294 @@ +setupBuiltinScalarScenario(); + $this->setupCustomScalarScenario(); + $this->setupTypeOfScenario(); + $this->setupCombinedScenario(); + } + + /** + * Scenario 1: 500 items × 8 built-in scalar fields = 4 000 serialize() calls. + * Built-in serialize() is cheap (type coercion), so gains here are modest. + */ + private function setupBuiltinScalarScenario(): void + { + $items = array_fill(0, 500, [ + 'id' => 1, + 'name' => 'Widget', + 'price' => 9.99, + 'active' => true, + 'stock' => 42, + 'rating' => 4.5, + 'views' => 1337, + 'score' => 99, + ]); + + $productType = new ObjectType([ + 'name' => 'Product', + 'fields' => [ + 'id' => ['type' => Type::int()], + 'name' => ['type' => Type::string()], + 'price' => ['type' => Type::float()], + 'active' => ['type' => Type::boolean()], + 'stock' => ['type' => Type::int()], + 'rating' => ['type' => Type::float()], + 'views' => ['type' => Type::int()], + 'score' => ['type' => Type::int()], + ], + ]); + + $this->builtinScalarSchema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'products' => [ + 'type' => Type::listOf($productType), + 'resolve' => static fn (): array => $items, + ], + ], + ]), + ]); + + $this->builtinScalarQuery = Parser::parse(new Source( + '{ products { id name price active stock rating views score } }' + )); + } + + public function benchBuiltinScalarFields(): void + { + GraphQL::executeQuery($this->builtinScalarSchema, $this->builtinScalarQuery); + } + + public function benchBuiltinScalarFieldsTrusted(): void + { + GraphQL::executeQuery($this->builtinScalarSchema, $this->builtinScalarQuery, trustResult: true); + } + + /** + * Scenario 2: 100 items × 5 custom scalar fields. The custom serialize() does real work + * (slug normalisation + validation), making the per-field cost measurable. + */ + private function setupCustomScalarScenario(): void + { + $items = array_fill(0, 100, [ + 'code' => 'WIDGET-001', + 'slug' => 'my-product-slug', + 'ref' => 'REF-ABC-123', + 'tag' => 'electronics/gadgets', + 'sku' => 'SKU-XYZ-999', + ]); + + // A scalar that lowercases and strips non-alphanumeric characters on serialize. + $slugScalar = new CustomScalarType([ + 'name' => 'Slug', + 'serialize' => static fn ($value): string => strtolower( + preg_replace('/[^a-z0-9\-]/i', '-', (string) $value) ?? (string) $value + ), + 'parseValue' => static fn ($value): string => (string) $value, + 'parseLiteral' => static fn ($ast): string => $ast->value, + ]); + + $itemType = new ObjectType([ + 'name' => 'Item', + 'fields' => [ + 'code' => ['type' => $slugScalar], + 'slug' => ['type' => $slugScalar], + 'ref' => ['type' => $slugScalar], + 'tag' => ['type' => $slugScalar], + 'sku' => ['type' => $slugScalar], + ], + ]); + + $this->customScalarSchema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'items' => [ + 'type' => Type::listOf($itemType), + 'resolve' => static fn (): array => $items, + ], + ], + ]), + ]); + + $this->customScalarQuery = Parser::parse(new Source( + '{ items { code slug ref tag sku } }' + )); + } + + public function benchCustomScalarFields(): void + { + GraphQL::executeQuery($this->customScalarSchema, $this->customScalarQuery); + } + + public function benchCustomScalarFieldsTrusted(): void + { + GraphQL::executeQuery($this->customScalarSchema, $this->customScalarQuery, trustResult: true); + } + + /** + * Scenario 3: 100 objects each triggering an isTypeOf() callback. + * trustResult skips all isTypeOf checks. + */ + private function setupTypeOfScenario(): void + { + $users = array_fill(0, 100, [ + '__typename' => 'User', + 'id' => 1, + 'name' => 'Alice', + 'email' => 'alice@example.com', + ]); + + $userType = new ObjectType([ + 'name' => 'User', + 'fields' => [ + 'id' => ['type' => Type::int()], + 'name' => ['type' => Type::string()], + 'email' => ['type' => Type::string()], + ], + 'isTypeOf' => static fn ($value): bool => is_array($value) + && ($value['__typename'] ?? null) === 'User', + ]); + + $this->typeOfSchema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'users' => [ + 'type' => Type::listOf($userType), + 'resolve' => static fn (): array => $users, + ], + ], + ]), + ]); + + $this->typeOfQuery = Parser::parse(new Source('{ users { id name email } }')); + } + + public function benchIsTypeOf(): void + { + GraphQL::executeQuery($this->typeOfSchema, $this->typeOfQuery); + } + + public function benchIsTypeOfTrusted(): void + { + GraphQL::executeQuery($this->typeOfSchema, $this->typeOfQuery, trustResult: true); + } + + /** + * Scenario 4: 30 orders with a nested customer object and 5 scalar fields each. + * Combines scalar serialization (30 × 8 = 240 calls) and nested object resolution. + */ + private function setupCombinedScenario(): void + { + $orders = array_fill(0, 30, [ + 'id' => 1, + 'status' => 'shipped', + 'total' => 99.99, + 'quantity' => 3, + 'note' => 'fragile', + 'customer' => ['id' => 42, 'name' => 'Bob', 'tier' => 'gold'], + ]); + + $customerType = new ObjectType([ + 'name' => 'Customer', + 'fields' => [ + 'id' => ['type' => Type::int()], + 'name' => ['type' => Type::string()], + 'tier' => ['type' => Type::string()], + ], + ]); + + $orderType = new ObjectType([ + 'name' => 'Order', + 'fields' => [ + 'id' => ['type' => Type::int()], + 'status' => ['type' => Type::string()], + 'total' => ['type' => Type::float()], + 'quantity' => ['type' => Type::int()], + 'note' => ['type' => Type::string()], + 'customer' => ['type' => $customerType], + ], + ]); + + $this->combinedSchema = new Schema([ + 'query' => new ObjectType([ + 'name' => 'Query', + 'fields' => [ + 'orders' => [ + 'type' => Type::listOf($orderType), + 'resolve' => static fn (): array => $orders, + ], + ], + ]), + ]); + + $this->combinedQuery = Parser::parse(new Source( + '{ orders { id status total quantity note customer { id name tier } } }' + )); + } + + public function benchCombinedQuery(): void + { + GraphQL::executeQuery($this->combinedSchema, $this->combinedQuery); + } + + public function benchCombinedQueryTrusted(): void + { + GraphQL::executeQuery($this->combinedSchema, $this->combinedQuery, trustResult: true); + } +} From 2c0e061ee9bc30dfa8fffcb2b837063369fbb80a Mon Sep 17 00:00:00 2001 From: Benedikt Franke Date: Sun, 15 Mar 2026 11:24:50 +0100 Subject: [PATCH 11/11] PHP 7.4 compat --- benchmarks/TrustResultBench.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/benchmarks/TrustResultBench.php b/benchmarks/TrustResultBench.php index 9e9c3c53e..ed388b03e 100644 --- a/benchmarks/TrustResultBench.php +++ b/benchmarks/TrustResultBench.php @@ -115,7 +115,7 @@ public function benchBuiltinScalarFields(): void public function benchBuiltinScalarFieldsTrusted(): void { - GraphQL::executeQuery($this->builtinScalarSchema, $this->builtinScalarQuery, trustResult: true); + GraphQL::executeQuery($this->builtinScalarSchema, $this->builtinScalarQuery, null, null, null, null, null, null, true); } /** @@ -177,7 +177,7 @@ public function benchCustomScalarFields(): void public function benchCustomScalarFieldsTrusted(): void { - GraphQL::executeQuery($this->customScalarSchema, $this->customScalarQuery, trustResult: true); + GraphQL::executeQuery($this->customScalarSchema, $this->customScalarQuery, null, null, null, null, null, null, true); } /** @@ -226,7 +226,7 @@ public function benchIsTypeOf(): void public function benchIsTypeOfTrusted(): void { - GraphQL::executeQuery($this->typeOfSchema, $this->typeOfQuery, trustResult: true); + GraphQL::executeQuery($this->typeOfSchema, $this->typeOfQuery, null, null, null, null, null, null, true); } /** @@ -289,6 +289,6 @@ public function benchCombinedQuery(): void public function benchCombinedQueryTrusted(): void { - GraphQL::executeQuery($this->combinedSchema, $this->combinedQuery, trustResult: true); + GraphQL::executeQuery($this->combinedSchema, $this->combinedQuery, null, null, null, null, null, null, true); } }