Skip to content

Commit 2766914

Browse files
committed
refactor: use in-place mutation to reduce array copies in OpenApiSchemaConverter
Change convertRecursive, handleNullable, handlePrefixItems, and removeKeys to accept arrays by reference instead of by value. This eliminates intermediate array copies created at each transformation step during recursive schema conversion, reducing memory allocations for deeply nested OpenAPI schemas.
1 parent 9936918 commit 2766914

1 file changed

Lines changed: 33 additions & 46 deletions

File tree

src/OpenApiSchemaConverter.php

Lines changed: 33 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
namespace Studio\OpenApiContractTesting;
66

77
use function array_is_list;
8-
use function array_map;
98
use function is_array;
109
use function is_string;
1110

@@ -44,92 +43,92 @@ final class OpenApiSchemaConverter
4443
*/
4544
public static function convert(array $schema, OpenApiVersion $version = OpenApiVersion::V3_0): array
4645
{
47-
return self::convertRecursive($schema, $version);
46+
self::convertInPlace($schema, $version);
47+
48+
return $schema;
4849
}
4950

5051
/**
5152
* @param array<string, mixed> $schema
52-
*
53-
* @return array<string, mixed>
5453
*/
55-
private static function convertRecursive(array $schema, OpenApiVersion $version): array
54+
private static function convertInPlace(array &$schema, OpenApiVersion $version): void
5655
{
5756
if ($version === OpenApiVersion::V3_0) {
58-
$schema = self::handleNullable($schema);
59-
$schema = self::removeKeys($schema, self::OPENAPI_3_0_KEYS);
57+
self::handleNullable($schema);
58+
self::removeKeys($schema, self::OPENAPI_3_0_KEYS);
6059
} else {
61-
$schema = self::handlePrefixItems($schema);
62-
$schema = self::removeKeys($schema, self::DRAFT_2020_12_KEYS);
60+
self::handlePrefixItems($schema);
61+
self::removeKeys($schema, self::DRAFT_2020_12_KEYS);
6362
}
6463

65-
$schema = self::removeKeys($schema, self::OPENAPI_COMMON_KEYS);
64+
self::removeKeys($schema, self::OPENAPI_COMMON_KEYS);
6665

6766
if (isset($schema['properties']) && is_array($schema['properties'])) {
68-
foreach ($schema['properties'] as $key => $property) {
67+
foreach ($schema['properties'] as &$property) {
6968
if (is_array($property)) {
70-
$schema['properties'][$key] = self::convertRecursive($property, $version);
69+
self::convertInPlace($property, $version);
7170
}
7271
}
72+
unset($property);
7373
}
7474

7575
if (isset($schema['items']) && is_array($schema['items'])) {
76-
// items can be an array (tuple from prefixItems conversion) or an object schema
7776
if (array_is_list($schema['items'])) {
78-
$schema['items'] = array_map(
79-
static fn(mixed $item): mixed => is_array($item) ? self::convertRecursive($item, $version) : $item,
80-
$schema['items'],
81-
);
77+
foreach ($schema['items'] as &$item) {
78+
if (is_array($item)) {
79+
self::convertInPlace($item, $version);
80+
}
81+
}
82+
unset($item);
8283
} else {
83-
$schema['items'] = self::convertRecursive($schema['items'], $version);
84+
self::convertInPlace($schema['items'], $version);
8485
}
8586
}
8687

8788
foreach (['allOf', 'oneOf', 'anyOf'] as $combiner) {
8889
if (isset($schema[$combiner]) && is_array($schema[$combiner])) {
89-
$schema[$combiner] = array_map(
90-
static fn(mixed $item): mixed => is_array($item) ? self::convertRecursive($item, $version) : $item,
91-
$schema[$combiner],
92-
);
90+
foreach ($schema[$combiner] as &$item) {
91+
if (is_array($item)) {
92+
self::convertInPlace($item, $version);
93+
}
94+
}
95+
unset($item);
9396
}
9497
}
9598

9699
if (isset($schema['additionalProperties']) && is_array($schema['additionalProperties'])) {
97-
$schema['additionalProperties'] = self::convertRecursive($schema['additionalProperties'], $version);
100+
self::convertInPlace($schema['additionalProperties'], $version);
98101
}
99102

100103
if (isset($schema['not']) && is_array($schema['not'])) {
101-
$schema['not'] = self::convertRecursive($schema['not'], $version);
104+
self::convertInPlace($schema['not'], $version);
102105
}
103-
104-
return $schema;
105106
}
106107

107108
/**
108109
* Convert OpenAPI 3.0 nullable to JSON Schema compatible type.
109110
*
110111
* @param array<string, mixed> $schema
111-
*
112-
* @return array<string, mixed>
113112
*/
114-
private static function handleNullable(array $schema): array
113+
private static function handleNullable(array &$schema): void
115114
{
116115
if (!isset($schema['nullable']) || $schema['nullable'] !== true) {
117-
return $schema;
116+
return;
118117
}
119118

120119
unset($schema['nullable']);
121120

122121
if (isset($schema['type']) && is_string($schema['type'])) {
123122
$schema['type'] = [$schema['type'], 'null'];
124123

125-
return $schema;
124+
return;
126125
}
127126

128127
foreach (['oneOf', 'anyOf'] as $combiner) {
129128
if (isset($schema[$combiner]) && is_array($schema[$combiner])) {
130129
$schema[$combiner][] = ['type' => 'null'];
131130

132-
return $schema;
131+
return;
133132
}
134133
}
135134

@@ -140,42 +139,30 @@ private static function handleNullable(array $schema): array
140139
['allOf' => $allOf],
141140
['type' => 'null'],
142141
];
143-
144-
return $schema;
145142
}
146-
147-
return $schema;
148143
}
149144

150145
/**
151146
* Convert Draft 2020-12 prefixItems to Draft 07 items array (tuple validation).
152147
*
153148
* @param array<string, mixed> $schema
154-
*
155-
* @return array<string, mixed>
156149
*/
157-
private static function handlePrefixItems(array $schema): array
150+
private static function handlePrefixItems(array &$schema): void
158151
{
159152
if (isset($schema['prefixItems']) && is_array($schema['prefixItems'])) {
160153
$schema['items'] = $schema['prefixItems'];
161154
unset($schema['prefixItems']);
162155
}
163-
164-
return $schema;
165156
}
166157

167158
/**
168159
* @param array<string, mixed> $schema
169160
* @param string[] $keys
170-
*
171-
* @return array<string, mixed>
172161
*/
173-
private static function removeKeys(array $schema, array $keys): array
162+
private static function removeKeys(array &$schema, array $keys): void
174163
{
175164
foreach ($keys as $key) {
176165
unset($schema[$key]);
177166
}
178-
179-
return $schema;
180167
}
181168
}

0 commit comments

Comments
 (0)