Skip to content

Commit cfb39c5

Browse files
bug #58917 [OptionsResolver] Allow Union/Intersection Types in Resolved Closures (zanbaldwin)
This PR was squashed before being merged into the 6.4 branch. Discussion ---------- [OptionsResolver] Allow Union/Intersection Types in Resolved Closures | Q | A | ------------- | --- | Branch? | 6.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Issues | _N/A_ | License | MIT Using intersection/union types in Closures set in OptionsResolver currently causes the fatal error: `Attempted to call an undefined method named "getName" of class "ReflectionUnionType".` in `vendor/symfony/options-resolver/OptionsResolver.php` (line 235). This can be re-created with following form type: ```php class ExampleType extends AbstractType { public function getParent(): string { return Type\ChoiceType::class; } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => MyEntity::class, // Assume MyEntity is Stringable. 'choice_value' => fn (MyEntity|string|null $entity): string => (string) $entity, ]); } } ``` Commits ------- 61ddfc4 [OptionsResolver] Allow Union/Intersection Types in Resolved Closures
2 parents 70f7d05 + 61ddfc4 commit cfb39c5

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

src/Symfony/Component/OptionsResolver/OptionsResolver.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public function setDefault(string $option, mixed $value): static
232232
return $this;
233233
}
234234

235-
if (isset($params[0]) && null !== ($type = $params[0]->getType()) && self::class === $type->getName() && (!isset($params[1]) || (($type = $params[1]->getType()) instanceof \ReflectionNamedType && Options::class === $type->getName()))) {
235+
if (isset($params[0]) && ($type = $params[0]->getType()) instanceof \ReflectionNamedType && self::class === $type->getName() && (!isset($params[1]) || (($type = $params[1]->getType()) instanceof \ReflectionNamedType && Options::class === $type->getName()))) {
236236
// Store closure for later evaluation
237237
$this->nested[$option][] = $value;
238238
$this->defaults[$option] = [];

src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php

+22
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,28 @@ public function testClosureWithoutParametersNotInvoked()
159159
$this->assertSame(['foo' => $closure], $this->resolver->resolve());
160160
}
161161

162+
public function testClosureWithUnionTypesNotInvoked()
163+
{
164+
$closure = function (int|string|null $value) {
165+
Assert::fail('Should not be called');
166+
};
167+
168+
$this->resolver->setDefault('foo', $closure);
169+
170+
$this->assertSame(['foo' => $closure], $this->resolver->resolve());
171+
}
172+
173+
public function testClosureWithIntersectionTypesNotInvoked()
174+
{
175+
$closure = function (\Stringable&\JsonSerializable $value) {
176+
Assert::fail('Should not be called');
177+
};
178+
179+
$this->resolver->setDefault('foo', $closure);
180+
181+
$this->assertSame(['foo' => $closure], $this->resolver->resolve());
182+
}
183+
162184
public function testAccessPreviousDefaultValue()
163185
{
164186
// defined by superclass

0 commit comments

Comments
 (0)