ServiceLocator vs controller->servicelocator

I have a Controller that extends AbstractActionController'. This line of code generates a deprecated message:

$config = $this->getServiceLocator()->get('Config');

But this line of code does not:

$config = $this->servicelocator->get('Config');

Question: Is this second version still following an anti-pattern?

More important Question: when ServiceLocatorAwareInterface is removed, will that 2nd version continue to work?

Same name, same result, same anti-pattern.

No because the whole concept is an anti-pattern.

See also in the migration guide of laminas-mvc.


But this does not mean that you have to write more factories now.
laminas-servicemanager and laminas-mvc can help here with some factories and autowiring:

Another option is to create configuration maps: Configuration-based Abstract Factory - laminas-servicemanager - Laminas Docs

For your example with the config this means:

class ExampleController extends Laminas\Mvc\Controller\AbstractActionController
{
    private array $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function indexAction()
    {
        $something = $this->config['something'];
    }
}
use Laminas\Mvc\Controller\LazyControllerAbstractFactory;

return [
    'controllers' => [
        'factories' => [
            MyModule\Controller\ExampleController::class => LazyControllerAbstractFactory::class,
        ],
    ],
    // …
];
  • A parameter named $config typehinted as an array will receive the application “config” service (i.e., the merged configuration).

https://docs.laminas.dev/laminas-mvc/cookbook/automating-controller-factories/

1 Like

yea… I suspected that was the answer that I’d get. :smirk:

The LazyControllerAbstractFactory sounds great but unavailable to me right now because the app is still a Zend Framework 2 .4 app under php 5.6. Our plan is to:

  1. Get rid of ServiceLocater anti-pattern,
  2. Refactor code that would be problematic under php 7.4
  3. Switch to php 7.4 (still a ZF2 app)
  4. Start using Composer for autoloading
  5. Convert it to Laminas-MVC.

(This was our first php app - written by coders new to php 4 years ago.)

We are still on step #1; unfortunately, there are MANY instances where we use Service Manager (ugh!)

Thank you, @froschdesign , you have been very helpful to many people in this forum (including me!). It is obvious that you know this framework very well.

Question: Do you think that we are proceeding in the correct sequence (steps 1-5 above)?
I wonder if it might be better to get rid of ServiceLocator after it is running under php 7.4 and converted to Laminas-MVC (obviously, we’d have to filter out the user_deprecated messages).

I think this could also work as a first step.

Can be done before.

Try to jump to version 2.7 of zend-mvc / zendframework, this works with PHP 5.6. Then you can use constructor injection for your controllers with the help of Zend\ServiceManager\AbstractFactory\ReflectionBasedAbstractFactory. The usage is the same as in laminas-servicemanager:

namespace MyModule\Controller;

use Zend\Form\FormElementManager;

class ExampleController extends Zend\Mvc\Controller\AbstractActionController
{
    /** @var FormElementManager */
    private $formElementManager;

    public function __construct(FormElementManager $formElementManager)
    {
        $this->formElementManager = $formElementManager;
    }

    public function indexAction()
    {
        $form = $this->formElementManager->get(ExampleForm::class);
    }
}
use Zend\ServiceManager\AbstractFactory\ReflectionBasedAbstractFactory;

return [
    'controllers' => [
        'factories' => [
            MyModule\Controller\ExampleController::class => ReflectionBasedAbstractFactory::class,
        ],
    ],
    // …
];