Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

doe_doe_doe's avatar

doe_doe_doe liked a comment+100 XP

2mos ago

From your last snippet, you can use the container to instantiate the service class, without pre-configuring a locator

use Illuminate\Contracts\Container\Container;

class MessageHandler
{
    public function __construct(
        // 1. Inject the container
        private readonly Container $container,
    ) {}

    public function handle(MessageInterface $message) {
        $voodooClass = $this->getVoodooAttributeClass($message);
        
        // 2. resolve the service from the container
        $voodooService = $this->container->make($voodooClass);
        $voodooService->doVoodoo($message);
    }
}

If you don't want to inject the container, use the gloabl helper:

class MessageHandler
{
    public function handle(MessageInterface $message) {
        $voodooClass = $this->getVoodooAttributeClass($message);

        // Use the global helper to resolve the service
        $voodooService = app($voodooClass);
        $voodooService->doVoodoo($message);
    }
}
doe_doe_doe's avatar

doe_doe_doe wrote a reply+100 XP

3mos ago

Is there a better solution for this in the VoodooLocator:

foreach ($voodooServices as $service) {
  $this->servicesByClass[get_class($service)] = $service;
}

Because all services get initialized - even if they are not used.

doe_doe_doe's avatar

doe_doe_doe started a new conversation+100 XP

3mos ago

Hi,

I'm relativly new to Laravel and currently I'm searching, which is the best way to design my app.

Let's say I have a MessageInterface and I have about 50x different implementations of this interface. And now I want to build different VoodooServices for these messages. Each message implementation could have a different VoodooService.

In Symfony there would be a nice solution for this: Service locator. I didn't find something similar in Laravel. What would be a good and flexible solution in Laravel?

In Symfony this would look like this:

Message class with attribute:

#[VoodooAttribute(FooVoodooService::class)]
class FooMessage() implements MessageInterface {
	...
}

VoodooInterface

#[AutoconfigureTag('voodoo')]
interface VoodooInterface {
  ...
}

Voodoo service

class FooVoodooService implements VoodooInterface {

  public function doVoodoo(MessageInterface $message): void {
    ...
  }

}

Service Locator

class VoodooLocator extends AbstractLocator {

  public function __construct(
    #[AutowireLocator('voodoo')]
    ServiceLocator $services
  ) {
    parent::__construct($services);
  }
  ...

MessageHandler

class MessageHandler {
  
  public function __constructor(
	private VoodooLocator $voodooLocator,
  )

  public function handle(MessageInterface $message) {
    $voodooClass = $this->getVoodooAttributeClass($message);
    $voodooService = $this->voodooLocator->getService($voodooClass);
    $voodooService->doVoodoo($message);
  }

}

So I have different message classes, where I can assign different voodoo services with an attribute. An easy and flexible design. Then I have a voodoo interface and a service locator. This locator contains all services, which have this voodoo interface. Then in the message handler I read out the voodoo class from the attribute, get the service from the locator and then do voodoo.

Service locators are considered an anti-pattern. But for me, the typical arguments against a service locator don't apply here, because this VoodooLocator contains only implementations of the VoodooInterface - not the whole container.

Now I search for a good and flexible solution in Laravel? Any tips?