Skip to content

Commit 5d949d9

Browse files
DerManoMannclaude
andcommitted
fix: PHP 8.5 deprecation for null as array offset
Use null-coalescing with Generator::UNDEFINED to guard against null key-field values in serialization and validation. Adds tests that trigger the deprecation on unpatched code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 2f117df commit 5d949d9

4 files changed

Lines changed: 39 additions & 5 deletions

File tree

src/Annotations/AbstractAnnotation.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ public function jsonSerialize(): \stdClass
308308
if (is_numeric($key) === false && is_array($item)) {
309309
$object->{$key} = $item;
310310
} else {
311-
$key = $item->{$keyField};
311+
$key = $item->{$keyField} ?? Generator::UNDEFINED;
312312
if (!Generator::isDefault($key) && empty($object->{$key})) {
313313
$object->{$key} = $item instanceof \JsonSerializable ? $item->jsonSerialize() : $item;
314314
unset($object->{$key}->{$keyField});
@@ -506,7 +506,7 @@ public function validate(?Analysis $analysis = null, string $version = OpenApi::
506506
if (is_array($item) && !is_numeric($key)) {
507507
$this->_context->logger->warning($this->identity() . '->' . $property . ' is an object literal, use nested ' . AbstractAnnotation::shorten($annotationClass) . '() annotation(s) in ' . $this->_context);
508508
$keys[$key] = $item;
509-
} elseif (Generator::isDefault($item->{$keyField})) {
509+
} elseif (Generator::isDefault($item->{$keyField} ?? Generator::UNDEFINED)) {
510510
$this->_context->logger->error($item->identity() . ' is missing key-field: "' . $keyField . '" in ' . $item->_context);
511511
} elseif (isset($keys[$item->{$keyField}])) {
512512
$this->_context->logger->error('Multiple ' . $item->identity([]) . ' with the same ' . $keyField . '="' . $item->{$keyField} . "\":\n " . $item->_context . "\n " . $keys[$item->{$keyField}]->_context);

src/Processors/AugmentParameters.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,14 @@ protected function augmentSharedParameters(Analysis $analysis): void
113113
$keys = [];
114114
$parametersWithoutKey = [];
115115
foreach ($analysis->openapi->components->parameters as $parameter) {
116-
if (!Generator::isDefault($parameter->parameter)) {
116+
if (!Generator::isDefault($parameter->parameter) && $parameter->parameter !== null) {
117117
$keys[$parameter->parameter] = $parameter;
118118
} else {
119119
$parametersWithoutKey[] = $parameter;
120120
}
121121
}
122122
foreach ($parametersWithoutKey as $parameter) {
123-
if (!Generator::isDefault($parameter->name) && empty($keys[$parameter->name])) {
123+
if (!Generator::isDefault($parameter->name) && $parameter->name !== null && empty($keys[$parameter->name])) {
124124
$parameter->parameter = $parameter->name;
125125
$keys[$parameter->parameter] = $parameter;
126126
}

src/Processors/AugmentTags.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ public function __invoke(Analysis $analysis): void
6161
$declaredTags = [];
6262
if (!Generator::isDefault($analysis->openapi->tags)) {
6363
foreach ($analysis->openapi->tags as $tag) {
64-
$declaredTags[$tag->name] = $tag;
64+
if (!empty($tag->name)) {
65+
$declaredTags[$tag->name] = $tag;
66+
}
6567
}
6668
}
6769
if ($declaredTags) {

tests/Annotations/AbstractAnnotationTest.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,38 @@ public function testIdentity(OA\AbstractAnnotation $annotation, ?array $identity
156156
{
157157
$this->assertSame($expected, $annotation->identity($identityArgs));
158158
}
159+
160+
public function testNullKeyFieldSerialize(): void
161+
{
162+
$response = new OA\Response([
163+
'response' => 200,
164+
'description' => 'Success',
165+
'headers' => [
166+
new OA\Header(['header' => null, '_context' => $this->getContext()]),
167+
new OA\Header(['header' => 'X-Token', '_context' => $this->getContext()]),
168+
],
169+
'_context' => $this->getContext(),
170+
]);
171+
172+
$json = $response->jsonSerialize();
173+
$this->assertObjectHasProperty('headers', $json);
174+
$this->assertObjectHasProperty('X-Token', $json->headers);
175+
}
176+
177+
public function testNullKeyFieldValidate(): void
178+
{
179+
$response = new OA\Response([
180+
'response' => 200,
181+
'description' => 'Success',
182+
'headers' => [
183+
new OA\Header(['header' => null, '_context' => $this->getContext()]),
184+
],
185+
'_context' => $this->getContext(),
186+
]);
187+
188+
$this->assertOpenApiLogEntryContains('is missing key-field: "header"');
189+
$response->validate();
190+
}
159191
}
160192

161193
class SubSchema extends OA\Schema

0 commit comments

Comments
 (0)