You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feature #24290 Adding Definition::addError() and a compiler pass to throw errors as exceptions (weaverryan)
This PR was squashed before being merged into the 3.4 branch (closes #24290).
Discussion
----------
Adding Definition::addError() and a compiler pass to throw errors as exceptions
| Q | A
| ------------- | ---
| Branch? | 3.4
| Bug fix? | yes & no
| New feature? | yes
| BC breaks? | no
| Deprecations? | yes (very minor)
| Tests pass? | yes
| Fixed tickets | #23606
| License | MIT
| Doc PR | Not needed
Hi guys!
Very simple: when there is an error with a Definition, we can now call `Definition::addError()` instead of throwing an exception. Then, a new compiler pass (after removal) actually throws an exception. The advantage is that we can avoid throwing exceptions for services that are ultimately removed from the container. That's important for auto-registration, where we commonly register all services in `src/`... but then many of them are removed later.
A few interesting notes:
- We can probably convert more things from exceptions to `Definition::addError()`. I've only converted autowiring errors and things in `CheckArgumentsValidityPass` (that was necessary because it was throwing exceptions in some cases due to autowiring failing... which was the true error)
- `Definition` can hold multiple errors, but I'm only showing the first error in the exception message. The reason is clarity: I think usually the first error is the most (or only) important. But having `Definition::addError()` avoids the possibility of a later error overriding an earlier one
Cheers!
Commits
-------
a85b37a Adding Definition::addError() and a compiler pass to throw errors as exceptions
@trigger_error('The '.__NAMESPACE__.'\AutowireExceptionPass class is deprecated since version 3.4 and will be removed in 4.0. Use the DefinitionErrorExceptionPass class instead.', E_USER_DEPRECATED);
* @deprecated since version 3.4, to be removed in 4.0.
48
+
*
47
49
* @return AutowiringFailedException[]
48
50
*/
49
51
publicfunctiongetAutowiringExceptions()
50
52
{
53
+
@trigger_error('Calling AutowirePass::getAutowiringExceptions() is deprecated since Symfony 3.4 and will be removed in 4.0. Use Definition::getErrors() instead.', E_USER_DEPRECATED);
54
+
51
55
return$this->autowiringExceptions;
52
56
}
53
57
@@ -106,6 +110,7 @@ protected function processValue($value, $isRoot = false)
@@ -35,10 +42,20 @@ protected function processValue($value, $isRoot = false)
35
42
foreach ($value->getArguments() as$k => $v) {
36
43
if ($k !== $i++) {
37
44
if (!is_int($k)) {
38
-
thrownewRuntimeException(sprintf('Invalid constructor argument for service "%s": integer expected but found string "%s". Check your service definition.', $this->currentId, $k));
45
+
$msg = sprintf('Invalid constructor argument for service "%s": integer expected but found string "%s". Check your service definition.', $this->currentId, $k);
46
+
$value->addError($msg);
47
+
if ($this->throwExceptions) {
48
+
thrownewRuntimeException($msg);
49
+
}
50
+
51
+
break;
39
52
}
40
53
41
-
thrownewRuntimeException(sprintf('Invalid constructor argument %d for service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $this->currentId, $i));
54
+
$msg = sprintf('Invalid constructor argument %d for service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $this->currentId, $i);
55
+
$value->addError($msg);
56
+
if ($this->throwExceptions) {
57
+
thrownewRuntimeException($msg);
58
+
}
42
59
}
43
60
}
44
61
@@ -47,10 +64,20 @@ protected function processValue($value, $isRoot = false)
47
64
foreach ($methodCall[1] as$k => $v) {
48
65
if ($k !== $i++) {
49
66
if (!is_int($k)) {
50
-
thrownewRuntimeException(sprintf('Invalid argument for method call "%s" of service "%s": integer expected but found string "%s". Check your service definition.', $methodCall[0], $this->currentId, $k));
67
+
$msg = sprintf('Invalid argument for method call "%s" of service "%s": integer expected but found string "%s". Check your service definition.', $methodCall[0], $this->currentId, $k);
68
+
$value->addError($msg);
69
+
if ($this->throwExceptions) {
70
+
thrownewRuntimeException($msg);
71
+
}
72
+
73
+
break;
51
74
}
52
75
53
-
thrownewRuntimeException(sprintf('Invalid argument %d for method call "%s" of service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $methodCall[0], $this->currentId, $i));
76
+
$msg = sprintf('Invalid argument %d for method call "%s" of service "%s": argument %d must be defined before. Check your service definition.', 1 + $k, $methodCall[0], $this->currentId, $i);
Copy file name to clipboardExpand all lines: Compiler/InlineServiceDefinitionsPass.php
+4Lines changed: 4 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -38,10 +38,14 @@ public function setRepeatedPass(RepeatedPass $repeatedPass)
38
38
*
39
39
* The key is the inlined service id and its value is the list of services it was inlined into.
40
40
*
41
+
* @deprecated since version 3.4, to be removed in 4.0.
42
+
*
41
43
* @return array
42
44
*/
43
45
publicfunctiongetInlinedServiceIds()
44
46
{
47
+
@trigger_error('Calling InlineServiceDefinitionsPass::getInlinedServiceIds() is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
0 commit comments