It's a *great* question :). Notice, that when you set $di['db'], you are not setting this *directly* to the PDO object, you are setting it to a callback function. To say it differently, after the code you have posted has executed (but before anything else has happened), the PDO instance has *not* been created yet: we've simply configured a Pimple\Container() object with a bunch of configuration and callback functions.
Later in your code, you will eventually want to *reference* your "db" service (e.g. $di['db']->someFunction()). At the *moment* that you do this, the Pimple\Container object will execute your callback function and pass itself (the container) as the first argument to that function. This whole setup is designed this way so that you can have a nice container full of objects, but can delay actually creating those object (for performance purposes) until (and unless) you actually need them.
Why does the Container pass itself as the first argument? I mean, how does it know that it's supposed to? Or are you trying to say that the creators of Pimple made it do so? Ok, I feel like I'm getting closer now. :) Could you pinpoint exactly where (like which files in the vendor folder) does this magic happen?
When you call your service for the first time and service declared as a callback (e.g. as an anonymous function) then Pimple call this callback and inject itself to it, and then the value that returns called callback stores under the same service key, i.e. your anonymous function overwrites with a real object it returns. You can see it here. So Pimple always injects itself into the callback, but you can miss this first argument in callback if you don't need it.
Excellent question! I would check out the first few chapters of this tutorial - https://symfonycasts.com/sc... - it's really about object-oriented coding, but it touches on this topic. The short answer is that a "service oriented architecture" if one where you isolate a lot of your "functionality" into individual service classes.
But let me explain that a bit better (hopefully) :p. Imagine you have a complex page that builds a form, has validation rule and maybe sends an email on success. The simplest way to write that is to put all that code right in the same place (inside the "controller" if you're using a framework like Symfony).
A service-oriented architecture says:
> Hey! You should identity the individual "chunks" of functionality (e.g. validation rules or sending the email) and isolate each one into its own, reusable, standalone function. Except that, in modern object-oriented coding, we isolate these into methods inside a class (called a service class) instead of flat functions.
So a service-oriented architecture sounds really cool and amazing, but it's really a simple idea that you're probably already doing: isolate parts of your code their own class so that they can be re-used and tested. This gives you a bunch of "tools" (service classes) for all your functionality.
Hello, I want to tell you that I love your course. however, I have a problem with the challenge when I want to pass it, I get this error: <blockquote><( ! ) Parse error: syntax error, unexpected '$container' (T_VARIABLE) in sendHappy.php on line 17</blockquote> the line is :
$container['happy_sender'] = function(Container $container) {
return new HappyMessageSender($container['email_loader']); // line 17 is herre
};
i have try this but same error again:
$container['happy_sender'] = function() use (Container $container) {
return new HappyMessageSender($container['email_loader']); // line 17 is herre
};
PS: i am new in your platform, i don't if here is a good place for talk about this but if no tell me where to do it. thank you
This is a great place to talk and ask questions about this! And, I'm sorry you're hitting this error! So, hmm. I don't see anything wrong with the code you have - I even pasted it into my editor to be absolutely sure. It looks perfect! So, this is a mystery! Here are a few possible things:
A) I don't think this is the case, but you may have a syntax error on the line above these (maybe around line 14 or 15) and PHP is mistakenly telling you the problem is on line 17. This can happen, for example, if you forget a ";" at the end of the line. But if this were the cause, I think PHP would report the error on line 16.
B) If you copied and pasted this code form somewhere, it's possible that it contains some invisible whitespace characters. This is rare, but super hard to debug. The best way to see if this is the problem is to delete these lines completely and re-type them by hand.
C) Finally, what version of PHP are you using? You could hack in a phpinfo();die; in any file, and the output would show you the version. But you would need to be using a *pretty old version (maybe 5.3?) in order for this code to be invalid.
Let me know what you find out! And welcome to SymfonyCasts :).
Injecting the container is not recommended because you are just hiding the dependencies among your services. It's much much better to use DI (Dependency injection) instead :)
Hm, your example a bit out of the context, it's not clear how those service was defined. Probably you're talking about some kind of service factory :) I can check into it if you provide some links where do you see those tests.
In our case, we do suppose that no matter how many times you fetch the mailer service from the container - it will be the same object, that was instantiated on the first fetch.
Ah, very good! Yes, indeed! Well, sort of :). Technically, yes: when you fetch a service from a container directly, that is service location. However, when you pass Pimple into the anonymous function ($container->share(function(Pimple $container) {})), you're really doing this so that you can configure the dependency injection of whatever service is being configured. Basically, Pimple's DI system depends on using Pimple as a service locator in this way. So, yes, this IS service location :). But, it's necessary due to how Pimple is built. When you use $container['some_service_id']outside of the anonymous function (like we do fetch the friend_harvester), that definitely is service location :).
Cheers!
Please, log in to vote for this comment
|
Share Comment
"Houston: no signs of life" Start the conversation!
14 Comments
How on earth does this $c variable receive the container instance?? :)
Hey Maksym!
It's a *great* question :). Notice, that when you set $di['db'], you are not setting this *directly* to the PDO object, you are setting it to a callback function. To say it differently, after the code you have posted has executed (but before anything else has happened), the PDO instance has *not* been created yet: we've simply configured a Pimple\Container() object with a bunch of configuration and callback functions.
Later in your code, you will eventually want to *reference* your "db" service (e.g. $di['db']->someFunction()). At the *moment* that you do this, the Pimple\Container object will execute your callback function and pass itself (the container) as the first argument to that function. This whole setup is designed this way so that you can have a nice container full of objects, but can delay actually creating those object (for performance purposes) until (and unless) you actually need them.
Let me know if that helps!
Cheers!
Hi, Ryan!
Thank you very much for replying!
Why does the Container pass itself as the first argument? I mean, how does it know that it's supposed to? Or are you trying to say that the creators of Pimple made it do so?
Ok, I feel like I'm getting closer now. :)
Could you pinpoint exactly where (like which files in the vendor folder) does this magic happen?
Hey Maksym,
When you call your service for the first time and service declared as a callback (e.g. as an anonymous function) then Pimple call this callback and inject itself to it, and then the value that returns called callback stores under the same service key, i.e. your anonymous function overwrites with a real object it returns. You can see it here. So Pimple always injects itself into the callback, but you can miss this first argument in callback if you don't need it.
Cheers!
Hi. You used term "service-oriented architecture". Can you point me where where I can read more about this?
Hey Maksym D.!
Excellent question! I would check out the first few chapters of this tutorial - https://symfonycasts.com/sc... - it's really about object-oriented coding, but it touches on this topic. The short answer is that a "service oriented architecture" if one where you isolate a lot of your "functionality" into individual service classes.
But let me explain that a bit better (hopefully) :p. Imagine you have a complex page that builds a form, has validation rule and maybe sends an email on success. The simplest way to write that is to put all that code right in the same place (inside the "controller" if you're using a framework like Symfony).
A service-oriented architecture says:
> Hey! You should identity the individual "chunks" of functionality (e.g. validation rules or sending the email) and isolate each one into its own, reusable, standalone function. Except that, in modern object-oriented coding, we isolate these into methods inside a class (called a service class) instead of flat functions.
So a service-oriented architecture sounds really cool and amazing, but it's really a simple idea that you're probably already doing: isolate parts of your code their own class so that they can be re-used and tested. This gives you a bunch of "tools" (service classes) for all your functionality.
Let me know if that helps!
Cheers!
Hello, I want to tell you that I love your course. however, I have a problem with the challenge when I want to pass it, I get this error:
<blockquote><( ! ) Parse error: syntax error, unexpected '$container' (T_VARIABLE) in sendHappy.php on line 17</blockquote>
the line is :
i have try this but same error again:
PS: i am new in your platform, i don't if here is a good place for talk about this but if no tell me where to do it.
thank you
Hi @Lacina!
This is a great place to talk and ask questions about this! And, I'm sorry you're hitting this error! So, hmm. I don't see anything wrong with the code you have - I even pasted it into my editor to be absolutely sure. It looks perfect! So, this is a mystery! Here are a few possible things:
A) I don't think this is the case, but you may have a syntax error on the line above these (maybe around line 14 or 15) and PHP is mistakenly telling you the problem is on line 17. This can happen, for example, if you forget a ";" at the end of the line. But if this were the cause, I think PHP would report the error on line 16.
B) If you copied and pasted this code form somewhere, it's possible that it contains some invisible whitespace characters. This is rare, but super hard to debug. The best way to see if this is the problem is to delete these lines completely and re-type them by hand.
C) Finally, what version of PHP are you using? You could hack in a
phpinfo();die;in any file, and the output would show you the version. But you would need to be using a *pretty old version (maybe 5.3?) in order for this code to be invalid.Let me know what you find out! And welcome to SymfonyCasts :).
Cheers!
Hi,
How bad is it to inject the container itself in a service? or to provide the container as a trait in an object.
$container['my_service'] = $funcion($c){
return MyService($c)
}
trait DIContainer{
public function getDIContainer(){
$containerObj = new DIContainer();
return $containerObj->getContainer();
}
}
I'm not sure this is possible with Pimple, and I can imagine you will then loose the overview of each service' dependencies.
It would be very nice (lazy :) ) to have access to all the services in an object.What's your opinion about this?
Hey Ferdinand geerman
Injecting the container is not recommended because you are just hiding the dependencies among your services. It's much much better to use DI (Dependency injection) instead :)
Cheers!
Checking pimple v.1for learning purposes, I see that this assertion appears on the tests
$serviceOne = $pimple['service'];
$serviceTwo = $pimple['service'];
$this->assertNotSame($serviceOne, $serviceTwo);
Which confuses me with the assertion appearing on the video:
$willBeTrue = $mailer1 === $mailer2;
Could you please elaborate a bit on it. Thanks.
Hey Calamarino,
Hm, your example a bit out of the context, it's not clear how those service was defined. Probably you're talking about some kind of service factory :) I can check into it if you provide some links where do you see those tests.
In our case, we do suppose that no matter how many times you fetch the mailer service from the container - it will be the same object, that was instantiated on the first fetch.
Cheers!
When you start injecting Pimple into anonymous functions, doesn't it become a Service Locator pattern instead of DI?
Hey George007!
Ah, very good! Yes, indeed! Well, sort of :). Technically, yes: when you fetch a service from a container directly, that is service location. However, when you pass Pimple into the anonymous function (
$container->share(function(Pimple $container) {})), you're really doing this so that you can configure the dependency injection of whatever service is being configured. Basically, Pimple's DI system depends on using Pimple as a service locator in this way. So, yes, this IS service location :). But, it's necessary due to how Pimple is built. When you use$container['some_service_id']outside of the anonymous function (like we do fetch the friend_harvester), that definitely is service location :).Cheers!
"Houston: no signs of life"
Start the conversation!