@@ -235,24 +235,76 @@ public function createService(string $name): object
235235 * Returns an instance of the autowired service of the given type. If it has not been created yet, it creates it.
236236 * @template T of object
237237 * @param class-string<T> $type
238+ * @param bool $throw throw exception if service doesn't exist?
238239 * @return ($throw is true ? T : ?T)
239240 * @throws MissingServiceException
240241 */
241242 public function getByType (string $ type , bool $ throw = true ): ?object
243+ {
244+ return $ this ->getByTypeAndTag ($ type , null , $ throw );
245+ }
246+
247+
248+ /**
249+ * Returns an instance of the autowired service of the given type and tag. If it has not been created yet, it creates it.
250+ * @template T of object
251+ * @param class-string<T> $type
252+ * @param bool $throw throw exception if service doesn't exist?
253+ * @return ($throw is true ? T : ?T)
254+ * @throws MissingServiceException
255+ */
256+ public function getByTypeAndTag (string $ type , ?string $ tag = null , bool $ throw = true ): ?object
242257 {
243258 $ type = Helpers::normalizeClass ($ type );
244259 if (!empty ($ this ->wiring [$ type ][0 ])) {
245- if (count ($ names = $ this ->wiring [$ type ][0 ]) === 1 ) {
246- return $ this ->getService ($ names [0 ]);
260+ $ names = $ this ->wiring [$ type ][0 ];
261+
262+ // Filter by tag if specified
263+ if ($ tag !== null ) {
264+ $ taggedNames = [];
265+ foreach ($ names as $ name ) {
266+ $ serviceTags = $ this ->findByTag ($ tag );
267+ if (isset ($ serviceTags [$ name ])) {
268+ $ taggedNames [] = $ name ;
269+ }
270+ }
271+ $ names = $ taggedNames ;
272+ }
273+
274+ // Try to find service with tag default
275+ if ($ tag === null && count ($ names ) > 1 ) {
276+ $ defaultTagNames = [];
277+ foreach ($ names as $ name ) {
278+ if (isset ($ this ->findByTag ('default ' )[$ name ])) {
279+ $ defaultTagNames [] = $ name ;
280+ }
281+ }
282+
283+ if ($ defaultTagNames !== []) {
284+ $ names = $ defaultTagNames ;
285+ }
247286 }
248287
249- natsort ($ names );
250- throw new MissingServiceException (sprintf ("Multiple services of type $ type found: %s. " , implode (', ' , $ names )));
288+ if (count ($ names ) === 1 ) {
289+ return $ this ->getService ($ names [0 ]);
290+ } elseif (count ($ names ) > 1 ) {
291+ natsort ($ names );
292+
293+ throw new MissingServiceException (sprintf (
294+ 'Multiple services of type %s%s found: %s. ' ,
295+ $ type ,
296+ $ tag !== null ? " with tag ' $ tag' " : '' ,
297+ implode (', ' , $ names ),
298+ ));
299+ }
300+ }
251301
252- } elseif ($ throw ) {
302+ if ($ throw ) {
253303 if (!class_exists ($ type ) && !interface_exists ($ type )) {
254304 throw new MissingServiceException (sprintf ("Service of type '%s' not found. Check the class name because it cannot be found. " , $ type ));
255- } elseif ($ this ->findByType ($ type )) {
305+ } elseif ($ tag !== null ) {
306+ throw new MissingServiceException (sprintf ("Service of type %s with tag '%s' not found. " , $ type , $ tag ));
307+ } elseif ($ this ->findByType ($ type ) !== []) {
256308 throw new MissingServiceException (sprintf ("Service of type %s is not autowired or is missing in di \u{a0}› \u{a0}export \u{a0}› \u{a0}types. " , $ type ));
257309 } else {
258310 throw new MissingServiceException (sprintf ('Service of type %s not found. Did you add it to configuration file? ' , $ type ));
@@ -359,7 +411,7 @@ public function callMethod(callable $function, array $args = []): mixed
359411 private function autowireArguments (\ReflectionFunctionAbstract $ function , array $ args = []): array
360412 {
361413 return Resolver::autowireArguments ($ function , $ args , fn (string $ type , bool $ single ) => $ single
362- ? $ this ->getByType ($ type )
414+ ? $ this ->getByType ($ type, throw: true )
363415 : array_map ($ this ->getService (...), $ this ->findAutowired ($ type )));
364416 }
365417
0 commit comments