@@ -34,6 +34,7 @@ public function __construct($loader = [])
3434 $ this ->container = $ loader ;
3535 }
3636
37+ /** @return mixed */
3738 public function __invoke (ServerRequestInterface $ request , callable $ next = null )
3839 {
3940 if ($ next === null ) {
@@ -117,6 +118,7 @@ public function getAccessLogHandler(): AccessLogHandler
117118 {
118119 if ($ this ->container instanceof ContainerInterface) {
119120 if ($ this ->container ->has (AccessLogHandler::class)) {
121+ // @phpstan-ignore-next-line method return type will ensure correct type or throw `TypeError`
120122 return $ this ->container ->get (AccessLogHandler::class);
121123 } else {
122124 return new AccessLogHandler ();
@@ -130,6 +132,7 @@ public function getErrorHandler(): ErrorHandler
130132 {
131133 if ($ this ->container instanceof ContainerInterface) {
132134 if ($ this ->container ->has (ErrorHandler::class)) {
135+ // @phpstan-ignore-next-line method return type will ensure correct type or throw `TypeError`
133136 return $ this ->container ->get (ErrorHandler::class);
134137 } else {
135138 return new ErrorHandler ();
@@ -139,22 +142,25 @@ public function getErrorHandler(): ErrorHandler
139142 }
140143
141144 /**
142- * @template T
145+ * @template T of object
143146 * @param class-string<T> $name
144147 * @return T
145148 * @throws \BadMethodCallException if object of type $name can not be loaded
146149 */
147150 private function loadObject (string $ name , int $ depth = 64 ) /*: object (PHP 7.2+) */
148151 {
152+ assert (\is_array ($ this ->container ));
153+
149154 if (\array_key_exists ($ name , $ this ->container )) {
150155 if (\is_string ($ this ->container [$ name ])) {
151156 if ($ depth < 1 ) {
152157 throw new \BadMethodCallException ('Factory for ' . $ name . ' is recursive ' );
153158 }
154159
160+ // @phpstan-ignore-next-line because type of container value is explicitly checked after getting here
155161 $ value = $ this ->loadObject ($ this ->container [$ name ], $ depth - 1 );
156162 if (!$ value instanceof $ name ) {
157- throw new \BadMethodCallException ('Factory for ' . $ name . ' returned unexpected ' . ( is_object ( $ value ) ? get_class ($ value) : gettype ( $ value ) ));
163+ throw new \BadMethodCallException ('Factory for ' . $ name . ' returned unexpected ' . \ get_class ($ value ));
158164 }
159165
160166 $ this ->container [$ name ] = $ value ;
@@ -171,6 +177,7 @@ private function loadObject(string $name, int $depth = 64) /*: object (PHP 7.2+)
171177 throw new \BadMethodCallException ('Factory for ' . $ name . ' is recursive ' );
172178 }
173179
180+ // @phpstan-ignore-next-line because type of container value is explicitly checked after getting here
174181 $ value = $ this ->loadObject ($ value , $ depth - 1 );
175182 }
176183 if (!$ value instanceof $ name ) {
@@ -210,10 +217,14 @@ private function loadObject(string $name, int $depth = 64) /*: object (PHP 7.2+)
210217 $ params = $ ctor === null ? [] : $ this ->loadFunctionParams ($ ctor , $ depth , false );
211218
212219 // instantiate with list of parameters
220+ // @phpstan-ignore-next-line because `$class->newInstance()` is known to return `T`
213221 return $ this ->container [$ name ] = $ params === [] ? new $ name () : $ class ->newInstance (...$ params );
214222 }
215223
216- /** @throws \BadMethodCallException if either parameter can not be loaded */
224+ /**
225+ * @return list<mixed>
226+ * @throws \BadMethodCallException if either parameter can not be loaded
227+ */
217228 private function loadFunctionParams (\ReflectionFunctionAbstract $ function , int $ depth , bool $ allowVariables ): array
218229 {
219230 $ params = [];
@@ -230,6 +241,8 @@ private function loadFunctionParams(\ReflectionFunctionAbstract $function, int $
230241 */
231242 private function loadParameter (\ReflectionParameter $ parameter , int $ depth , bool $ allowVariables ) /*: mixed (PHP 8.0+) */
232243 {
244+ assert (\is_array ($ this ->container ));
245+
233246 $ type = $ parameter ->getType ();
234247 $ hasDefault = $ parameter ->isDefaultValueAvailable () || ((!$ type instanceof \ReflectionNamedType || $ type ->getName () !== 'mixed ' ) && $ parameter ->allowsNull ());
235248
@@ -277,6 +290,7 @@ private function loadParameter(\ReflectionParameter $parameter, int $depth, bool
277290 throw new \BadMethodCallException (self ::parameterError ($ parameter ) . ' is recursive ' );
278291 }
279292
293+ // @phpstan-ignore-next-line because `$type->getName()` is a `class-string` by definition
280294 return $ this ->loadObject ($ type ->getName (), $ depth - 1 );
281295 }
282296
@@ -286,19 +300,21 @@ private function loadParameter(\ReflectionParameter $parameter, int $depth, bool
286300 */
287301 private function loadVariable (string $ name , string $ type , bool $ nullable , int $ depth ) /*: object|string|int|float|bool|null (PHP 8.0+) */
288302 {
289- assert (\array_key_exists ($ name , $ this ->container ) || isset ($ _SERVER [$ name ]));
303+ assert (\is_array ( $ this -> container ) && ( \ array_key_exists ($ name , $ this ->container ) || isset ($ _SERVER [$ name ]) ));
290304
291305 if (($ this ->container [$ name ] ?? null ) instanceof \Closure) {
292306 if ($ depth < 1 ) {
293307 throw new \BadMethodCallException ('Container variable $ ' . $ name . ' is recursive ' );
294308 }
295309
296310 // build list of factory parameters based on parameter types
297- $ closure = new \ReflectionFunction ($ this ->container [$ name ]);
311+ $ factory = $ this ->container [$ name ];
312+ assert ($ factory instanceof \Closure);
313+ $ closure = new \ReflectionFunction ($ factory );
298314 $ params = $ this ->loadFunctionParams ($ closure , $ depth - 1 , true );
299315
300316 // invoke factory with list of parameters
301- $ value = $ params === [] ? ( $ this -> container [ $ name ]) () : ( $ this -> container [ $ name ]) (...$ params );
317+ $ value = $ params === [] ? $ factory () : $ factory (...$ params );
302318
303319 if (!\is_object ($ value ) && !\is_scalar ($ value ) && $ value !== null ) {
304320 throw new \BadMethodCallException ('Container variable $ ' . $ name . ' expected type object|scalar|null from factory, but got ' . \gettype ($ value ));
0 commit comments