diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index e42d7bbfd168..e0578af71781 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -854,8 +854,13 @@ public function offsetGet($option) // dependency // BEGIN $this->calling[$option] = true; - foreach ($this->lazy[$option] as $closure) { - $value = $closure($this, $value); + try { + foreach ($this->lazy[$option] as $closure) { + $value = $closure($this, $value); + } + } catch (\Exception $e) { + unset($this->calling[$option]); + throw $e; } unset($this->calling[$option]); // END @@ -953,7 +958,12 @@ public function offsetGet($option) // dependency // BEGIN $this->calling[$option] = true; - $value = $normalizer($this, $value); + try { + $value = $normalizer($this, $value); + } catch (\Exception $e) { + unset($this->calling[$option]); + throw $e; + } unset($this->calling[$option]); // END } diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php index 0c2dce1af45e..367ee3fecdf7 100644 --- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php +++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolver2Dot6Test.php @@ -1103,6 +1103,56 @@ public function testFailIfCyclicDependencyBetweenNormalizerAndLazyOption() $this->resolver->resolve(); } + public function testCatchedExceptionFromNormalizerDoesNotCrashOptionResolver() + { + $throw = true; + + $this->resolver->setDefaults(array('catcher' => null, 'thrower' => null)); + + $this->resolver->setNormalizer('catcher', function (Options $options) { + try { + return $options['thrower']; + } catch(\Exception $e) { + return false; + } + }); + + $this->resolver->setNormalizer('thrower', function (Options $options) use (&$throw) { + if ($throw) { + $throw = false; + throw new \UnexpectedValueException('throwing'); + } + + return true; + }); + + $this->resolver->resolve(); + } + + public function testCatchedExceptionFromLazyDoesNotCrashOptionResolver() + { + $throw = true; + + $this->resolver->setDefault('catcher', function (Options $options) { + try { + return $options['thrower']; + } catch(\Exception $e) { + return false; + } + }); + + $this->resolver->setDefault('thrower', function (Options $options) use (&$throw) { + if ($throw) { + $throw = false; + throw new \UnexpectedValueException('throwing'); + } + + return true; + }); + + $this->resolver->resolve(); + } + public function testInvokeEachNormalizerOnlyOnce() { $calls = 0;