3

Pimple is a simple dependency injection container in php used in silex framework. I was going through the source code here. In the documentation the function offsetGet returns the same instance of the class that is attached to the dependency container. the relevant code for offsetGet is :

public function offsetGet($id)
{
    if (!isset($this->keys[$id])) {
        throw new InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
    }

    if (
        isset($this->raw[$id])
        || !is_object($this->values[$id])
        || isset($this->protected[$this->values[$id]])
        || !method_exists($this->values[$id], '__invoke')
    ) {
        return $this->values[$id];
    }

    if (isset($this->factories[$this->values[$id]])) {
        return $this->values[$id]($this);
    }

    $this->frozen[$id] = true;
    $this->raw[$id] = $this->values[$id];

    return $this->values[$id] = $this->values[$id]($this);
 }

Here, if the object is in the factories Object Store(SplObjectStorage type), it returns a new instance of the class with id $id. then in the last return again $this->values[$id] is set to a new instance of the object and that new instance is returned.

return $this->values[$id] = $this->values[$id]($this).

This is the line I fail to understand. How is this line supposed to return the same instance for different calls of offsetGet for the same $id. Won't it return a new instance every time? Please help me. I tried a lot but I don't get it.

Shikhar Subedi
  • 606
  • 1
  • 9
  • 26
  • `$this` just inject the object, which is instantiated before, not while returning – Royal Bg Nov 25 '13 at 14:26
  • i understand that $this is passed because the anonymous function requires the object of the container. this anonymous function returns a new instance of the class. – Shikhar Subedi Nov 25 '13 at 14:28
  • so aren't then instances related to the id's - tbh I haven't used this lib – Royal Bg Nov 25 '13 at 14:32
  • yes they are related to the ids. – Shikhar Subedi Nov 25 '13 at 14:34
  • So what is the problem with using the same instance. As I understood, you are afraid if it will return new instance everytime. Then the answer should be No, unless different id is passed? – Royal Bg Nov 25 '13 at 14:35
  • i dont understand what you are saying. could you please make an answer and give me an explanation – Shikhar Subedi Nov 25 '13 at 14:36
  • I'm unsure in my theory, so better not :) Let's wait for someone who has used this lib. – Royal Bg Nov 25 '13 at 14:38
  • I just looked up at the code once again, you have multiple returns, and yes, the line you have mentioned will return new instance, not the same. Before it, you have two other returns, one which returns the identifier if values[id] is not object – Royal Bg Nov 25 '13 at 14:43
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/41881/discussion-between-shikhar-subedi-and-royal-bg) – Shikhar Subedi Nov 25 '13 at 14:44

1 Answers1

3

I looked at the source code of pimple and found out that once the object is instantiated and kept in $this->values[$id], the next call of offsetGet will return from the second if condition. i.e this if condition:

if (
    isset($this->raw[$id])
    || !is_object($this->values[$id])
    || isset($this->protected[$this->values[$id]])
    || !method_exists($this->values[$id], '__invoke')
) {
    return $this->values[$id];
}

Looking at the unit tests, i found out that the objects without the magic method __invoke can be shared . If the object has a magic method __invoke(i.e the object can be treated as a function) , a new instance is returned everytime. So, you can see that the first, second and third condition on the above if statement return false . but the fourth condition returns true and hence the $this->values[$id] returns the same instance every time.

Shikhar Subedi
  • 606
  • 1
  • 9
  • 26