1212namespace Symfony \Component \DependencyInjection \Compiler ;
1313
1414use Symfony \Component \DependencyInjection \Argument \IteratorArgument ;
15+ use Symfony \Component \DependencyInjection \Container ;
1516use Symfony \Component \DependencyInjection \Definition ;
1617use Symfony \Component \DependencyInjection \Exception \InvalidArgumentException ;
1718use Symfony \Component \DependencyInjection \Exception \InvalidParameterTypeException ;
@@ -79,27 +80,27 @@ protected function processValue($value, $isRoot = false)
7980 /**
8081 * @throws InvalidArgumentException When not enough parameters are defined for the method
8182 */
82- private function checkTypeDeclarations (Definition $ checkedDefinition , \ReflectionFunctionAbstract $ reflectionFunction , array $ configurationArguments ): void
83+ private function checkTypeDeclarations (Definition $ checkedDefinition , \ReflectionFunctionAbstract $ reflectionFunction , array $ values ): void
8384 {
8485 $ numberOfRequiredParameters = $ reflectionFunction ->getNumberOfRequiredParameters ();
8586
86- if (\count ($ configurationArguments ) < $ numberOfRequiredParameters ) {
87- throw new InvalidArgumentException (sprintf ('Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed. ' , $ this ->currentId , $ reflectionFunction ->class , $ reflectionFunction ->name , $ numberOfRequiredParameters , \count ($ configurationArguments )));
87+ if (\count ($ values ) < $ numberOfRequiredParameters ) {
88+ throw new InvalidArgumentException (sprintf ('Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed. ' , $ this ->currentId , $ reflectionFunction ->class , $ reflectionFunction ->name , $ numberOfRequiredParameters , \count ($ values )));
8889 }
8990
9091 $ reflectionParameters = $ reflectionFunction ->getParameters ();
91- $ checksCount = min ($ reflectionFunction ->getNumberOfParameters (), \count ($ configurationArguments ));
92+ $ checksCount = min ($ reflectionFunction ->getNumberOfParameters (), \count ($ values ));
9293
9394 for ($ i = 0 ; $ i < $ checksCount ; ++$ i ) {
9495 if (!$ reflectionParameters [$ i ]->hasType () || $ reflectionParameters [$ i ]->isVariadic ()) {
9596 continue ;
9697 }
9798
98- $ this ->checkType ($ checkedDefinition , $ configurationArguments [$ i ], $ reflectionParameters [$ i ]);
99+ $ this ->checkType ($ checkedDefinition , $ values [$ i ], $ reflectionParameters [$ i ]);
99100 }
100101
101102 if ($ reflectionFunction ->isVariadic () && ($ lastParameter = end ($ reflectionParameters ))->hasType ()) {
102- $ variadicParameters = \array_slice ($ configurationArguments , $ lastParameter ->getPosition ());
103+ $ variadicParameters = \array_slice ($ values , $ lastParameter ->getPosition ());
103104
104105 foreach ($ variadicParameters as $ variadicParameter ) {
105106 $ this ->checkType ($ checkedDefinition , $ variadicParameter , $ lastParameter );
@@ -110,63 +111,82 @@ private function checkTypeDeclarations(Definition $checkedDefinition, \Reflectio
110111 /**
111112 * @throws InvalidParameterTypeException When a parameter is not compatible with the declared type
112113 */
113- private function checkType (Definition $ checkedDefinition , $ configurationArgument , \ReflectionParameter $ parameter ): void
114+ private function checkType (Definition $ checkedDefinition , $ value , \ReflectionParameter $ parameter ): void
114115 {
115- $ parameterTypeName = $ parameter ->getType ()->getName ();
116+ $ type = $ parameter ->getType ()->getName ();
116117
117- $ referencedDefinition = $ configurationArgument ;
118+ if ($ value instanceof Reference) {
119+ if (!$ this ->container ->has ($ value = (string ) $ value )) {
120+ return ;
121+ }
118122
119- if ($ referencedDefinition instanceof Reference) {
120- if (!$ this ->container ->has ($ referencedDefinition )) {
123+ if ('service_container ' === $ value && is_a ($ type , Container::class, true )) {
121124 return ;
122125 }
123126
124- $ referencedDefinition = $ this ->container ->findDefinition (( string ) $ referencedDefinition );
127+ $ value = $ this ->container ->findDefinition ($ value );
125128 }
126129
127- if ('self ' === $ parameterTypeName ) {
128- $ parameterTypeName = $ parameter ->getDeclaringClass ()->getName ();
130+ if ('self ' === $ type ) {
131+ $ type = $ parameter ->getDeclaringClass ()->getName ();
129132 }
130- if ('static ' === $ parameterTypeName ) {
131- $ parameterTypeName = $ checkedDefinition ->getClass ();
133+
134+ if ('static ' === $ type ) {
135+ $ type = $ checkedDefinition ->getClass ();
132136 }
133137
134- if ($ referencedDefinition instanceof Definition) {
135- $ class = $ referencedDefinition ->getClass ();
138+ if ($ value instanceof Definition) {
139+ $ class = $ value ->getClass ();
136140
137141 if (!$ class || (!$ this ->autoload && !class_exists ($ class , false ) && !interface_exists ($ class , false ))) {
138142 return ;
139143 }
140144
141- if (!is_a ($ class , $ parameterTypeName , true )) {
142- throw new InvalidParameterTypeException ($ this ->currentId , $ class , $ parameter );
143- }
144- } else {
145- if (null === $ configurationArgument && $ parameter ->allowsNull ()) {
145+ if ('callable ' === $ type && method_exists ($ class , '__invoke ' )) {
146146 return ;
147147 }
148148
149- if (\in_array ( $ parameterTypeName , self :: SCALAR_TYPES , true ) && is_scalar ( $ configurationArgument )) {
149+ if (' iterable ' === $ type && is_subclass_of ( $ class , ' Traversable ' )) {
150150 return ;
151151 }
152152
153- if (' iterable ' === $ parameterTypeName && $ configurationArgument instanceof IteratorArgument ) {
153+ if (is_a ( $ class , $ type , true ) ) {
154154 return ;
155155 }
156156
157- if ('Traversable ' === $ parameterTypeName && $ configurationArgument instanceof IteratorArgument) {
158- return ;
159- }
157+ throw new InvalidParameterTypeException ($ this ->currentId , $ class , $ parameter );
158+ }
160159
161- if ($ configurationArgument instanceof Parameter) {
162- return ;
163- }
160+ if ($ value instanceof Parameter) {
161+ $ value = $ this ->container ->getParameter ($ value );
162+ } elseif (\is_string ($ value ) && '% ' === ($ value [0 ] ?? '' ) && preg_match ('/^%([^%]+)%$/ ' , $ value , $ match )) {
163+ $ value = $ this ->container ->getParameter ($ match [1 ]);
164+ }
164165
165- $ checkFunction = sprintf ('is_%s ' , $ parameter ->getType ()->getName ());
166+ if (null === $ value && $ parameter ->allowsNull ()) {
167+ return ;
168+ }
166169
167- if (!$ parameter ->getType ()->isBuiltin () || !$ checkFunction ($ configurationArgument )) {
168- throw new InvalidParameterTypeException ($ this ->currentId , \gettype ($ configurationArgument ), $ parameter );
169- }
170+ if (\in_array ($ type , self ::SCALAR_TYPES , true ) && is_scalar ($ value )) {
171+ return ;
172+ }
173+
174+ if ('callable ' === $ type && \is_array ($ value ) && isset ($ value [0 ]) && ($ value [0 ] instanceof Reference || $ value [0 ] instanceof Definition)) {
175+ return ;
176+ }
177+
178+ if ('iterable ' === $ type && (\is_array ($ value ) || $ value instanceof \Traversable || $ value instanceof IteratorArgument)) {
179+ return ;
180+ }
181+
182+ if ('Traversable ' === $ type && ($ value instanceof \Traversable || $ value instanceof IteratorArgument)) {
183+ return ;
184+ }
185+
186+ $ checkFunction = sprintf ('is_%s ' , $ parameter ->getType ()->getName ());
187+
188+ if (!$ parameter ->getType ()->isBuiltin () || !$ checkFunction ($ value )) {
189+ throw new InvalidParameterTypeException ($ this ->currentId , \gettype ($ value ), $ parameter );
170190 }
171191 }
172192}
0 commit comments