Laravel 5.6 Documentation says:
There is no need to bind classes into the container if they do not
depend on any interfaces. The container does not need to be instructed
on how to build these objects, since it can automatically resolve
these objects using reflection.
I don't understand it.
Does it mean that I don't have to use any bindigs inside provider's register method if I don't use interfaces?
Then, how can I use dependency injection if I don't use bindigs?
P.S.:
in my understending:
"interface" - is this
"bindings" - is bind() and singelton() inside register
If you have :
class Something {
}
You can do app()->make(Something::class) without needing to bind it before hand. The container knows that it can just call the default constructor.
The same goes for
class SomethingElse {
public function __construct(Something $s) { }
}
In this case the constructor will also go through the dependency injection. This is all handled automatically by the container.
However this obviously cannot work for interfaces since interfaces can't be constructed.
Also if you need something to be bound as a singleton you need to bind it explicitly using app()->singleton(...)
Related
I'm looking at Laravel's service container docs, specifically the binding section.
What are the differences and when should I use each type of binding? The documentation mentions:
Simple Binding
Singleton Binding
Instance Binding
Primitive binding
Interface binding
First, let's see what it actually is:
IoC container is a component that knows how instances are created. It also knows of all their underlying dependencies and how to resolve them.
Container's knowledge about instance creation and dependency resolving might be guided by the programmer. That's why Laravel's container provides various binding APIs for me, and you.
"Resolving out of the container" is a phrase you read/hear a lot. It means that you tell the container to make something for you based on the [optional] guidance you gave her previously.
Before you continue reading about bindings, I strongly recommend you to read this answer:
What is Laravel IoC Container in simple words?
Simple Binding
app()->bind(DatabaseWriter::class, function ($app) {
return new DatabaseWriter(
$app->make(DatabaseAdapterInterface)
);
});
You say to the container that when you want to resolve an instance of DatabaseWriter class, follow this logic I just told you in the closure coz I know better. Every single time that you want to resolve the class, you must follow this and deliver me a new instance.
You use this type of bindings all the time. You're giving the container small recipes on how to make your things for you.
Singleton Binding
Same as simple bindings, with one obvious difference. You're telling the container that I want only one instance of this class across my whole application. The first time you're resolving the class, follow the logic in the closure I passed to you, but be sure that you just return that only instance every other time you want to resolve it. Deliver me the only instance you were allowed to make.
It's a singleton, right? Once a singleton binding is resolved, the same object instance will be returned on subsequent calls into the container.
Obviously, you use this type of binding when you want to utilize the Singleton pattern. It's rare these days.
Instance Binding
It's like doing a favor for the container. You don't tell her how to instantiate a certain class, you do it yourself and just give her the instance. She holds it for you and returns it on subsequent calls into the container.
It's especially handy when you're unit-testing. If you bind a mock instance to the container for some class, all the subsequent calls to app()->make() will return that mock for you. So you're practically injecting a class mock all over the app when the actual class is used.
class QuestionsControllerTest extends TestCase
{
public function testQuestionListing()
{
$questionMock = Mockery::mock('Question')
->shouldReceive('latest')
->once()
->getMock();
// You're telling the container that everytime anyone
// wants a Question instance, give them this mock I just
// gave you.
$this->app->instance('Question', $this->questionMock);
// whatever...
}
}
Primitive Binding
Laravel's container provides a DSL for you to tell her how to resolve primitives as well. You say when BillingController class wants a $taxRate variable and it's not passed, give it 0.2. It's like setting default values from far far away!
app()->when('App\Http\Controllers\BillingController')
->needs('$taxRate')
->give(.2);
The use-case might be rare, but you might need them occasionally. This example might be a lil bit more sensual:
app()->when('App\Http\Controllers\CustomerController')
->needs('$customers')
->give(function() {
return Customer::paying();
});
Interface Binding
It's used when you want to bind interfaces to concrete implementations.
After reading a dozen articles on SOLID and how to be a better programmer, you decide to follow Dependency Inversion principle and instead of depending on concrete instances, you depend on abstractions.
After all, it's a good practice, in or out of Laravel.
class DatabaseWriter {
protected $db;
// Any concrete implementation of this interface will do
// Now, that I depend on this DatabaseAdapterInterface contract,
// I can work with MySQL, MongoDB and WhatevaDB! Awesome!
public function __construct(DatabaseAdapterInterface $db)
{
$this->db = $db;
}
public function write()
{
$this->db->query('...');
}
}
Without Laravel's container, you first need to create a concrete implementation of DatabaseAdapterInterface and pass it through DatabaseWriter's constructor to be able to instantiate it:
$dbWriter = new DatabaseWriter(new MongodbAdapter)
If MongodbAdapter has its own dependencies, you might end up here:
// Looks familiar, right?
// These are those recipes you used to give to Laravel container
// through simple binding.
$dbWriter = new DatabaseWriter(new MongodbAdapter(new MongodbConnection))
But with Laravel's container in the party, you tell her that when anyone asks for a concrete implementation of DatabaseAdapterInterface, ask no more and give them a MongodbAdapter:
app()->bind(DatabaseAdapterInterface::class, MongodbAdapter::class)
Then you go on and resolve an instance of DatabaseWriter out of container, like a boss:
$dbWriter = app()->make(DatabaseWriter::class)
Much easier and cleaner, right? You remove all the obvious clutter and move it to somewhere else. Your AppServiceProvider maybe.
OK, let's see how she works in this scenario. First, she probes DatabaseWriter for possible dependencies (through reflection), sees that it needs a DatabaseAdapterInterface. Checks her notebook, recalls that you told her that MongodbAdapter is the concrete implementation of that interface. Makes one and hand it over to DatabaseWriter.
You use these type of bindings almost all the time, if you're adhering to dependency inversion principle.
OK, enough with the chatter, let's see how she really works:
https://github.com/laravel/framework/blob/5.3/src/Illuminate/Container/Container.php#L627
Why should someone use this:
function flash($title)
{
$flash = app('App\Http\Flash');
return $flash->message('This is a flash message');
}
over this:
use App\Http\Flash;
function flash($title)
{
$flash = new Flash;
return $flash->message('This is a flash message');
}
In the first case we are getting the available container instance.
In the second case we load the Flash class and instantiate it then in our flash method.
I've seen someone use the first approach and I wonder if there is ANY difference in using the second approach.
If you are using it as in your example - you'll get no profit. But Laravel container gives much more power in this resolving that you cannot achieve with simple instantiating objects.
Binding Interface - you can bind specific interface and it's implementation into container and resolve it as interface. This is useful for test-friendly code and flexibility - cause you can easily change implementation in one place without changing interface. (For example use some Countable interface everywhere as a target to resolve from container but receive it's implementation instead.)
Dependency Injection - if you will bind class/interface and ask it as a dependecy in some method/constructor - Laravel will automatically insert it from container for you.
Conditional Binding - you can bind interface but depending on the situation resolve different implementations.
Singleton - you can bind some shared instance of an object.
Resolving Event - each time container resolves smth - it raises an event you can subscribe in other places of your project.
And many other practises...
You can read more detailed here http://laravel.com/docs/5.1/container
Bit of a long winded question, but here goes. I'm a little confused regarding some of the documentation for the service container in Laravel 5.1. I'll explain my current understanding of the container first, and then explain where my confusion has arisen.
So, I'm fairly sure I understand the process of registering a binding with the service container. To quote the documentation, you register a binding using the bind method, passing the class or interface name that we wish to register along with a Closure that returns an instance of the class:
$this->app->bind('HelpSpot\API', function ($app) {
return new HelpSpot\API($app['HttpClient']);
});
Now, in the Laravel 5.0 docs, that's actually stated slightly differently:
A Closure resolver is registered in the container with a key (typically the class name) and a Closure that returns some value.
So, in Laravel 5.0, it seems you were able to bind some class, say FooBar to a key that, while recommended to be the class name, could be something different, so for example:
$this->app->bind('myfoobarclass', function($app) {
return new FooBar($app['SomethingElse']);
});
And then later you could resolve the class using:
$fooBar = $this->app->make('myfoobarclass');
However, this would remove your ability ro resolve that class using type hinting, which I'm guessing is why the docs for 5.1 states specifically to use the class name. However, in the section on Facades (http://laravel.com/docs/5.1/facades#facade-class-reference), they list the facades along with their "service container binding key", which is different to their class name. Does this mean you can't resolve these facades using type hinting? Why would they register their bindings as something other than their class name? Or is this documentation simply out of date?
If anyone could shed some light on the reasons behind this inconsistency that would be amazing, thanks in advance.
You normally bind implementations to interfaces. So instead of adding something to the service container by the name of the class, you would instead use the name of an interface it implements instead:
$this->app->bind('App\HttpClientInterface', function ($app) {
return new \Guzzle\HttpClient;
});
You can then type-hint the HttpClientInterface interface in your application, and instead get the bound GuzzleHttpClient instance. This allows you to swap your implementations out in one place without having to re-write your application code.
You’re not restricted to using fully-qualified class/interface names, you can use arbitrary strings as key names if you wish:
$this->app->bind('http.client', function () {
return new \Guzzle\HttpClient;
});
But you can’t type-hint on these; this is where you would use the app()->make('http.client') method instead.
In regards to the Façade Class Reference section of the Laravel documentation, there are two ways of resolving the services in your app.
You can type-hint on the value in the Class column, i.e. Illuminate\Contracts\Hashing\Hasher
Alternatively, you can use what’s in the Service Container Binding column with the app()->make('hash') method. These are just “aliases” for the class name.
Hope this helps!
I'm making my own primitive MVC framework with PHP, and I'm wondering where I should load/instantiate corresponding controller dependencies?
In the constructor of each controller (tightly coupled) or inject them (loosely coupled)?
The only part of the latter that I'm not too sure of is for the dependencies to be instantiated on bootstrap level, outside of the MVC paradigm, before being injected. Not every controller uses the exact same dependencies besides the default parent ones. I would have to instantiate them all, which would also create a lot of overhead.
I've seen some existing frameworks do it like $this->load->model('model'); // CodeIgniter in the constructor, but I have no clue on why they're doing it like that.
I would suggest you inject the dependencies, so your controllers are less coupled to your framework. This will make a switch to another framework easier.
About instantiating dependencies: I suggest you use (or implement) a dependency injection container. This container should contain factories that can instantiate services.
In an ideal situation your controllers are services too (meaning they too have factories in the dependency injection container).
This way only the controller you need for a particular request will be instantiated, and therefor only its dependencies are instantiated.
When building you own framework, this means that after the routing phase (when the correct controller is known), the framework should grab that controller from the container. The container itself will make sure all dependencies that are needed will be provided.
Have a look at Pimple for an example of a simple dependency injection container.
PS: That line from CodeIgniter looks a lot like the service locator pattern. This pattern is similar to dependency injection, but does not provide full inversion of control.
Q: Where should i load/instantiate corresponding controller dependencies?
There are multiple ways.
The load and instantiation concepts are basically "before/outside" and "after/inside".
Before and outside means, that you load the file containing a class (which you want to instantiate and pass to the controller), before you load the controller.
But how do you know, what the controller needs, before loading the controller? Uh..
Dependency Description Files
A description file comes into play, describing the wiring between your controller and it's dependencies. In other words, you can see the dependencies of your controller by looking at it's dependency description file. This concept is often used by Dependency Injection tools, which analyze the object and pull the dependencies names out automatically. It's also possible to maintain such a wiring configuration file manually. But it's tedious.
Service Locator
A Service Locator is a instantiation helper for dependencies.
Basically, it contains the same information like a dependency description file, but this time in form of a registry. The link between parts of your application becomes this registry.
Both strategies introduce overhead. It's a trade-off. When you change the perspective and look at things from an application with maybe 500+ classes, then you realize that a dependency injection tool is sometimes worth it.
Manual Injection
via Constructor Injection.
After and inside means, that you load the file containing your controller and then start to care about the dependencies.
At this point the class is not instantiated, yet, but the autoloader might do it's dirty deeds behind the scene. He evaluates the use statements at the top of your controller file. The use statements declare namespaced classes, which the autoloader resolves to actuall files and loads them. You might then start to use these classes as dependencies in your controller. This is probably the easiest way to solve your problem and i strongly suggest looking into the topics autoloading with namespaces and use-statements.
When the class is instantiated, you have the following possiblities:
use might use Setter Injection or Reference Injection to set the dependencies to the object. This requires that your Constructor Dependencies are already solved or your constructor is empty.
It's possible to combine these strategies.
Q: What does this do $this->load->model('model'); // CodeIgniter?
CodeIgniter is a legacy application framework. It was created in times, when namespaced autoloading wasn't available. $this->load is a basic class loading helper. This is the opposite of an "auto"loader, (which surprise, surprise) loads things automatically.
CodeIgniters loader class is used to load various other classes, like libraries or files from the view, helpers, models or user defined stuff. This is again the concept of a registry. Here the registry just knowns where things are in your application layout and resolves them. So $this->load->model('model'); means that the modelfunction must have some piecies of information, about the position of model files in your application.
You provide a model name and the path for the file is constructed by model.
And this is exaclty what it does (except a bit of overhead): https://github.com/EllisLab/CodeIgniter/blob/develop/system/core/Loader.php#L223.
Since I'm a Symfony developer, I can only give you a reference to Symfony.
I think you should do like they are doing in Symfony by thinking about what you need in each
Controller object.
At least, you need :
a Request object
and a Model loader object that gives you every Model you need.
Create a BaseController that implements these few functions and then extend it with custom Controllers.
You can also take a look on Silex : http://silex.sensiolabs.org/ a Micro Framework
Hope it helps.
When do you say "In the constructor" you mean to pass in the conatiner and pull the dependencies from them (in the constructor)?
<?php
class SomeController
{
public function __construct($container)
{
$this->service1 = $contanier->get('service1);
}
//...
}
I advice against that, though simpler and easier you will be coupling your controllers to the container thus using a ServiceLocator instead of truly inversion of control.
If you want your controllers to be easy unit-testable you should use inversion of control:
class SomeController
{
public function __construct($service1)
{
$this->service1 = $service1;
}
//...
}
And you can even create your controller as a service inside the container:
// this uses Pimple notation, I hope you get the point
$container['controller'] = function($c) {
return SomeController($c['service1']);
}
Use proxy services to lazy load them
Also if your controllers needs more than some services and you won't be using all of them you can:
1) Use proxy services in order to lazy load the service only when they are really needed
<?php
class ProxyService
{
/**
* #var Service1Type
*/
private $actualService;
public function __construct()
{
$this->actualService = null;
}
private function initialize()
{
$this->actualService = new Service1(); // This operation may take some time thus we deferred as long as possible
}
private function isInitialized()
{
return $this->actualService === null;
}
public function someActionOnThisService()
{
if (!$this->isInitalized()) {
$this->initalize();
}
$this->actualService->someActionOnThisService();
}
There you have a simple proxy object with lazy loading. You may want to check the fantastic Proxy Manager Library if you want to go that route
2) Split your controller
If your contoller has too many dependencies, you may want to split it.
In fact you may want to read the proposal by Paul M. Jones (lead developer of Aura Framework) about MVC-Refinement, IMHO is a good read even though you may not fully agree with it.
Even if you split your controller in order to reduce the dependencies, lazy loading your dependencies is a good idea (obviously you'll have to check weather if its doable in your context: more work in order to gain more speed).
Maybe you need to define __autoload() function before you try to load the Classes which is not loaded yet. Like:
function __autoload($className) {
require "/path/to/the/class/file/$className.php";
}
My example is very very simple to auto require the file which the class definition is in.
You can also use if-else statement or switch statement in that function to fit your own situations smartly.
The __autoload() function is called when PHP doesn't find the class definition, works for new, class_exists(), call_user_method(), etc, and absolutely for your dependences/parents classes. If there is still no class definition after __autoload() is called, PHP will generate an error.
Or you can use spl_autoload_register() function instead of __autoload() more gracefully.
For more information, you might want to see:
http://php.net/manual/en/function.autoload.php
http://php.net/manual/en/function.spl-autoload-register.php
I am currently building an MVC application in PHP (not using any frameworks). I am using yadif (https://github.com/beberlei/yadif) for dependency injection.
I would like to build a login module. It should be able to use adapters, for example one might be able to set that logins are authenticated using the MySql database or some LDAP directory. This setting would be done in the admin area and is stored in a database.
I imagine that I would have an abstract adapter:
<?php
abstract AbstractLoginAdapter{
abstract function login($username, $pass){}
}
I would then just implement adapters like so:
<?php
MySQLLoginAdapter extends AbstractLoginAdapter{
public function login($username, $pass){
//do stuff
}
}
That's all nice and well, but how do I create an instance of the adapter? Usually, dependencies would be injected using yadif via the constructor:
<?php
class loginController{
private $_adapter;
public function __construct(AbstractLoginAdapter $adapter){
$this->_adapter = $adapter;
}
}
However, since I don't know which concrete adapter will be injected, I can't set that in a configuration before hand. Yadif allows me to create a configuration which I then need to pass to the container:
$builder = new Yadif_Builder();
$builder->bind("loginController")
->to("loginController")
->args($SelectedLoginAdapter);
Since the application uses a front controller, a DI container is created there. It then creates a routing object etc.
In light of this, should I pass a reference of that container down to the loginController object, and then use that container to instantiate my adapter?
Or should I instantiate a new container within my loginController object and then just load in an instance of the adapter?
I would do the first: pass a reference down to your controller. You'll want to use a single Dependency Injector Container (DIC) in your application. You don't want to create a new DIC whenever you need access to it. That would lead to duplication of objects stored in the DIC.
I know this is how Symfony 2 does it. All controllers (and many other classes) implement the ContainerAware interface. That interface has a single method setContainer() that is used to pass down a reference to the DIC.
I don't know about your specific DI tool but from a DI point of view you would be specifying which type to use. The container itself is responsible for instantiating a new instance (and possibly of all the dependencies of that type as well) of the configured type.
The benefit of DI in your example would be that you could deploy exactly the same code with a different configuration with 1 installation using LDAP and the other using MySQL authentication.
Refactor type hinting ("AbstractLoginAdapter") to ("MySQLLoginAdapter").
If you call abstract class method in the new __CLASS__ // Fatal Error.