Solved thread

This post is marked as solved. If you think the information contained on this thread must be part of the official documentation, please contribute submitting a pull request to its repository.

Best practise for accessing services

I'm going to write a complex application (backend) with a bunch of custom services. I know that there are different methods for accessing these services from controllers, forms, components and so on, but I want to ask you, which approach do you use, and why?

I.e. at the beginning of writing my code, I've used

$cookies = $this->di->get('cookies');

$cookie = $cookies->get('mycookie')->getValue();

But as I'm using cookies and other services from inside Volt like

{{ cookies.get('mycookie') == 'active' ? ... }}

To make it more solid, I decided to access services directly from inside controllers, forms and components like

$cookie = $this->cookies->get('mycookie')->getValue();

But I don't feel very comfortable with that, because it seems to me, that this way of accessing services involves magic getters. So, I always have to pay attention that I do not overload or overwrite a class variable which could be service name. So, how do you do it?

I prefere $this->di->getShared('cookies'); or Phalcon\Di::getDefault()->getShared('cookies') be careful with get() and getShared()

For more organization you can have service providers

use Phalcon\Di\ServiceProviderInterface;
use Phalcon\DiInterface;
use Phalcon\Di;
use Phalcon\Config\Adapter\Ini;

class SomeServiceProvider implements ServiceProviderInterface
{
    public function register(DiInterface $di)
    {
        $di->setShared(
            __CLASS__, 
            function () {
                return new Ini('config.ini');
            }
        );
    }
}

$di = new Di();
$di->register(new SomeServiceProvider());
var_dump($di->getShared(SomeServiceProvider::class)); // will return properly our config

Good luck



1.3k

Oh, thanks for pointing me to service providers. I use a bootstrap class similar to Phalcons website, that is fine for me now. But I'll keep service providers in mind. I think, when the app is growing it's not too late for switching from bootstrap class to more well-organized service providers.

Hum, using $this->di->getShared('cookies'); is more clean, but when I'm looking into compiled Volt templates then I can see that built-in methods like {{ javascript_include() }} compile to <?= $this->tag->javascriptInclude() ?>. So even Volt is using this simple notation for accessing services.

Hum, using $this->di->getShared('cookies'); is more clean, but when I'm looking into compiled Volt templates then I can see that built-in methods like {{ javascript_include() }} compile to <?= $this->tag->javascriptInclude() ?>. So even Volt is using this simple notation for accessing services.

By default magic method __get() use getShared() souce



133.2k
Accepted
answer

All depends on performance pretty much. If you will for example do $this->di->get('cookies'); multiple times it will be slower than $this->cookies because once you will access it it will be added as property to object and next calls will be just call directly to property with avoiding di at all. Of course assigning it to variable is good choice and performance should be the same.

Indeed you need to make sure you don't create property with name of service.



1.3k

Great, thanks for your ideas and knowledge. As I mentioned already, Volt compiles to $this->cookies, so I'll just do the same and access services directly. I take care with object methods and properties, where properties get prefixed with underscore.

edited 22d ago

you can write a helper function di as follows:

<?php
if (!function_exists('di')) {
    /**
     * @param string $name
     * @param array  $params
     *
     * @return mixed
     */
    function di($name = null, $params = null)
    {
        static $di;
        if (!$di) {
            $di = Di::getDefault();
        }
        if ($name === null || $name === 'di') {
            return $di;
        } elseif ($params) {
            return $di->getInstance($name, $params);
        } else {
            return $di->getShared($name);
        }
    }
}

ManaPHP implements many helper functions you can as a reference: https://github.com/manaphp/manaphp/blob/develop/ManaPHP/helpers.php

if you use phpstorm and like code completion you can create a .phpstorm.meta.php file as https://github.com/manaphp/manaphp/blob/develop/ManaPHP/.phpstorm.meta.php#L73