We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Doubt about set and setshared

Hello,

I know diference between both, I try instance a class from service.php with set and setShared and works ok but i want to check singleton with setshared, so if I call my class with setshared and i put a log into constructor I supuse i see this log the first time that I call this class, but not happen, because i see all the time this log into constructor as same with set(with set shall be normal)

Is this beahevior normal?

I think you're using get() instead of getShared()

I wrote this test script:

$DI = new \Phalcon\DI\FactoryDefault();

$DI->set('multi',function(){
    echo 'calling multi function<br />';
});
$DI->setShared('singleton',function(){
    echo 'calling singleton function<br />';
});
$DI->setShared('singletonshared',function(){
    echo 'calling singletonshared function<br />';
});

$DI->get('multi');
$DI->get('multi');
$DI->get('singleton');
$DI->get('singleton');
$DI->getShared('singletonshared');
$DI->getShared('singletonshared');

and got this output

calling multi function
calling multi function
calling singleton function
calling singleton function
calling singletonshared function

I see in the documentation that it says just setting with setShared() is enough to make it singleton, but that would seem to not be the case. Using getShared() should work.

edited Jun '20

Ok, I built a little more robust script:

$DI = new \Phalcon\DI\FactoryDefault();

$DI->set('multi',function(){
    return (object)['name'=>'multi','time'=>microtime(TRUE)];
});
$DI->setShared('singleton',function(){
    return (object)['name'=>'singleton','time'=>microtime(TRUE)];
});
$DI->setShared('shared',function(){
    return (object)['name'=>'shared','time'=>microtime(TRUE)];
});

echo '<pre>';
print_r($DI->get('multi'));
usleep(1000);
print_r($DI->get('multi'));
usleep(1000);
print_r($DI->get('singleton'));
usleep(1000);
print_r($DI->get('singleton'));
usleep(1000);
print_r($DI->getSingleton());
usleep(1000);
print_r($DI->getShared('shared'));
usleep(1000);
print_r($DI->getShared('shared'));
echo '</pre>';

And got this output:

stdClass Object
(
    [name] => multi
    [time] => 1591049103.716
)
stdClass Object
(
    [name] => multi
    [time] => 1591049103.7171
)
stdClass Object
(
    [name] => singleton
    [time] => 1591049103.7182
)
stdClass Object
(
    [name] => singleton
    [time] => 1591049103.7182
)
stdClass Object
(
    [name] => singleton
    [time] => 1591049103.7182
)
stdClass Object
(
    [name] => shared
    [time] => 1591049103.7214
)
stdClass Object
(
    [name] => shared
    [time] => 1591049103.7214
)

As you can see, the timestamps on the second invocation of both the singleton and shared service don't change, showing that the service creation function isn't being called on subsequent calls to get().

The important difference between my first and second script is the second script returns an object from the creation function. Phalcon must store that internally - thus if a creation function doesn't return an object, there's nothing to store, so Phalcon calls the function again on subsequent calls to get()

Could you post the code that registers the service and the test code you've written?



3.1k
edited Jun '20

Ok, i see it ok, but not in my example, maybe I am wrong.

My Class:

<?php
namespace Something\Classes;
use Something\Classes\HelloClass;

class HelloClass {
    public function __construct() {
        $this->logger = new \Phalcon\Logger\Adapter\File(BASE_PATH . '/tmp/logs/error.log');
        $this->logger->info('__construct');
    }

    public function setName($name) {
        $this->logger->info('name: ' . $name);
    }
}

My services.php

use Something\Classes\HelloClass;
$di->setShared('HelloClass', function () {
    return new HelloClass();
});

My Controller where I instance again HelloClass.php

<?php

namespace Something\Controllers;

use Something\Classes\HelloClass;

class IndexController extends ControllerBase
{
    public function indexAction()
    {
        $helloClass = new HelloClass();
        $this->HelloClass->setName('David');
    }   
}

Output: _construct _construct name: David



125.7k
Accepted
answer
edited Jun '20

That makes sense. You're calling the constructor twice.

The first time you're calling the constructor is in the controller:

$helloClass = new HelloClass();

The second time you're calling the constructor is in the function you've set as the service, which is only run when you ask for the service.

There's a couple things to note:

  1. Creating a new object from the class has nothing to do with the service of the same name. They're completely different.
  2. The DI does lazy loading, so the anonymous function you assigned to the HelloClassservice isn't run until you ask for the service with $this->HelloClass

If you add another line below that:

$this->HelloClass->setName('James');

Your output will be

__construct 
__construct 
name: David
name: James


3.1k

You right Dylan, tnahk you for you support in this forum. Regards.

Glad to help. Please Accept my answer to mark the thread as "[Solved]".

edited Aug '20

Ok, I built a little more robust script:

$DI = new \Phalcon\DI\FactoryDefault();

$DI->set('multi',function(){
   return (object)['name'=>'multi','time'=>microtime(TRUE)];
});
$DI->setShared('singleton',function(){
   return (object)['name'=>'singleton','time'=>microtime(TRUE)];
});
$DI->setShared('shared',function(){
   return (object)['name'=>'shared','time'=>microtime(TRUE)];
});

echo '<pre>';
print_r($DI->get('multi'));
usleep(1000);
print_r($DI->get('multi'));
usleep(1000);
print_r($DI->get('singleton'));
usleep(1000);
print_r($DI->get('singleton'));
usleep(1000);
print_r($DI->getSingleton());
usleep(1000);
print_r($DI->getShared('shared'));
usleep(1000);
print_r($DI->getShared('shared'));
echo '</pre>';  

And got this output:

stdClass Object
(
   [name] => multi
   [time] => 1591049103.716
)
stdClass Object
(
   [name] => multi
   [time] => 1591049103.7171
)
stdClass Object
(
   [name] => singleton
   [time] => 1591049103.7182
)
stdClass Object
(
   [name] => singleton
   [time] => 1591049103.7182
)
stdClass Object
(
   [name] => singleton
   [time] => 1591049103.7182
)
stdClass Object
(
   [name] => shared
   [time] => 1591049103.7214
)
stdClass Object
(
   [name] => shared
   [time] => 1591049103.7214
)

As you can see, the timestamps on the second invocation of both the singleton and shared service don't change, showing that the service creation function isn't being called on subsequent calls to get().

The important difference between my first and second script is the second script returns an object from the creation function. Phalcon must store that internally - thus if a creation function doesn't return an object, there's nothing to store, so Phalcon calls the function again on subsequent calls to get()

Could you post the code that registers the service and the test code you've written? Walgreens Listens

Thanks, very impressive. Really I appreciate you to continue your work. thank you for helping