Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Phalcon\Di - marking as "not shared" does not work if preceded by second invocation of ->set(). #1306

Closed
temuri416 opened this issue Sep 28, 2013 · 4 comments

Comments

@temuri416
Copy link
Contributor

It seems that "isShared" argument of Phalcon\DI:set() and $di->getService('whatever')->setShared(false); are ignored and service is always treated as "shared".

Case #1, a service registered as "shared" can be changed to "not shared", behaviour is as expected:

class Whatever
{
    public $val;
}

$di = new Phalcon\Di;

$di->set('whatever', function(){
    $o = new Whatever;
    $o->val = mt_rand(1, 10000000);
    return $o;
}, true); // Shared

echo '#1: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#2: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#3: ' . $val = $di->get('whatever')->val . PHP_EOL;

$di->getService('whatever')->setShared(false); // Don't share it anymore

echo '#4: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#5: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#6: ' . $val = $di->get('whatever')->val . PHP_EOL;

produces:

#1: 1398457 
#2: 1398457
#3: 1398457
#4: 3761278
#5: 4161252
#6: 5482824

As you see, first three times it's the same number, generated once during the first call and returned two more times. Invocations #4 and on return a new random number each time.

Case #2, same code as above, with one extra line:

$di = new Phalcon\Di;

$di->set('whatever', function(){
    $o = new Whatever;
    $o->val = mt_rand(1, 10000000);
    return $o;
}, true); // Shared

echo '#1: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#2: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#3: ' . $val = $di->get('whatever')->val . PHP_EOL;

// Fetch "whatever" from DI and set it back, mark it  as "not shared".
// This is the only different line of code.
$di->set('whatever', $di->get('whatever'), false);

$di->getService('whatever')->setShared(false);

echo '#4: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#5: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#6: ' . $val = $di->get('whatever')->val . PHP_EOL;

produces:

#1: 5880184
#2: 5880184
#3: 5880184
#4: 5880184
#5: 5880184
#6: 5880184

Here, the injection of

$di->set('whatever', $di->get('whatever'), false);

messes up remaining invocations, permanently turning 'whatever' into "shared" service. The following is ignored:

$di->getService('whatever')->setShared(false);

I'm on Phalcon 1.3.0, PHP5.5.1.

Thanks!

@nexik
Copy link

nexik commented Sep 28, 2013

Because your code is forcing DI to resolve whatever as object (concrete instance) not as service.

$di->set('whatever', $di->get('whatever'), false);

if you want to reconfigure service you should use getRaw or getService instead of get.

@nexik
Copy link

nexik commented Sep 28, 2013

One more thing.

$di->set('foo', new Foo());

is the same as

$di->set('foo', function(){ return new Foo()}, true);

so in first example setting shared to true is meaningless

@temuri416
Copy link
Contributor Author

@nexik

Re your second remark: why is it meaningless? TRUE causes new instantiation each time, FALSE always returns the same random number set during the only instantiation.

Let me rephrase the question. There's still something fishy.

The code:

$di->set('whatever', function(){
    $o = new Whatever;
    $o->val = mt_rand(1, 10000000);
    return $o;
}, false); // Not Shared

echo '#1: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#2: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#3: ' . $val = $di->get('whatever')->val . PHP_EOL;

$di->set('whatever', $di->get('whatever'), false); // Fetch and set back, not shared.

echo '#4: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#5: ' . $val = $di->get('whatever')->val . PHP_EOL;
echo '#6: ' . $val = $di->get('whatever')->val . PHP_EOL;

produces:

#1: 4324391
#2: 4920363
#3: 1208786
#4: 4856107
#5: 4856107    <-- toggled to "shared"
#6: 4856107    <-- toggled to "shared"

Question: why does

$di->set('whatever', $di->get('whatever'), false);

alter the behaviour and an existing instance is always returned (i.e. "shared"), despite the third argument of ->set() being set to FALSE ("not shared") ?

Thanks.

@nexik
Copy link

nexik commented Sep 28, 2013

$di->get('whatever')

don't return definition how to create new Whatever object but resolve object.

$di->set('whatever', $di->get('whatever'), false);

This is equal to

$o = new Whatever;
$o->val = mt_rand(1, 10000000);
$di->set('whatever', $o)

every time you run $di->get('whatever') will return object created before creation of service whatever.

This is how PHP works not Dependency Injection Container

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants