Skip to content

Commit 7fcbf72

Browse files
committed
refactor: replace JSON encode/decode roundtrip with direct array-to-object conversion
Replace json_encode() → json_decode() roundtrip in OpenApiResponseValidator with a recursive toObject() helper that directly converts PHP arrays to stdClass objects. This eliminates temporary JSON string allocations that doubled memory usage for large response bodies and schemas during validation.
1 parent a836231 commit 7fcbf72

1 file changed

Lines changed: 33 additions & 17 deletions

File tree

src/OpenApiResponseValidator.php

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,17 @@
44

55
namespace Studio\OpenApiContractTesting;
66

7-
use const JSON_THROW_ON_ERROR;
87
use const PHP_INT_MAX;
98

109
use InvalidArgumentException;
1110
use Opis\JsonSchema\Errors\ErrorFormatter;
1211
use Opis\JsonSchema\Validator;
12+
use stdClass;
1313

14+
use function array_is_list;
1415
use function array_keys;
1516
use function implode;
16-
use function json_decode;
17-
use function json_encode;
17+
use function is_array;
1818
use function sprintf;
1919
use function str_ends_with;
2020
use function strstr;
@@ -132,20 +132,8 @@ public function validate(
132132
$schema = $content[$jsonContentType]['schema'];
133133
$jsonSchema = OpenApiSchemaConverter::convert($schema, $version);
134134

135-
// opis/json-schema requires an object, so encode then decode
136-
$schemaObject = json_decode(
137-
(string) json_encode($jsonSchema, JSON_THROW_ON_ERROR),
138-
false,
139-
512,
140-
JSON_THROW_ON_ERROR,
141-
);
142-
143-
$dataObject = json_decode(
144-
(string) json_encode($responseBody, JSON_THROW_ON_ERROR),
145-
false,
146-
512,
147-
JSON_THROW_ON_ERROR,
148-
);
135+
$schemaObject = self::toObject($jsonSchema);
136+
$dataObject = self::toObject($responseBody);
149137

150138
$resolvedMaxErrors = $this->maxErrors === 0 ? PHP_INT_MAX : $this->maxErrors;
151139
$validator = new Validator(
@@ -171,6 +159,34 @@ public function validate(
171159
return OpenApiValidationResult::failure($errors, $matchedPath);
172160
}
173161

162+
/**
163+
* Recursively convert PHP arrays to stdClass objects, matching the
164+
* behaviour of json_decode(json_encode($data)) without the intermediate
165+
* JSON string allocation.
166+
*/
167+
private static function toObject(mixed $value): mixed
168+
{
169+
if (!is_array($value)) {
170+
return $value;
171+
}
172+
173+
if ($value === [] || array_is_list($value)) {
174+
/** @var list<mixed> $value */
175+
foreach ($value as $i => $item) {
176+
$value[$i] = self::toObject($item);
177+
}
178+
179+
return $value;
180+
}
181+
182+
$object = new stdClass();
183+
foreach ($value as $key => $item) {
184+
$object->{$key} = self::toObject($item);
185+
}
186+
187+
return $object;
188+
}
189+
174190
/**
175191
* Find the first JSON-compatible content type from the response spec.
176192
*

0 commit comments

Comments
 (0)