Laravel 5 offers automatic dependency resolving if I type-hint the needed class/interface. But how should they be instantiated? Example:
public function __construct(Dependency $dependency) {
$this->dependency = $dependency;
}
And then, in another method, I'd like to create two instances, like this:
$one = new Dependency(1);
$two = new Dependency(2);
What is the most flexible and test-friendly way to do this?
Excuse my poor joke, but it depends.
It looks like you have misunderstood the dependency resolving a little bit.
In your example the property 'dependency' allready contains an instantiated object. If you need two different instances within another method you may instantiate them there, inject a container or use a factory. It depends on your needs.
a very short introduction to laravel dependency resolving
The automatic dependency resolving in laravel is provided by the service container and it is used to deliver an (allready) instantiated object. The resolved object must be binded to service container. The best way to do this is via service providers. Within the register method of a service provider you are able to do your bindings
$this->app->bind('Dependency', function ($app) {
return new Dependency();
});
In this example the container will return a new instance every time it is called.
If you need the same instance every time you may bind a singleton
$this->app->singleton('Dependency', function ($app) {
return new Dependency();
});
Related
How does reflection in Laravel actually work?
I tried to debug it to see how Laravel uses reflection in a controller's constructor or methods to resolve their dependencies and sub-dependencies and then and give it back to us.
But I found it hard, and it's very complicated to see and to even understand 50% of. Jumping from class to class, I can't really see it. I tried a few times by debugging it with low results of understanding.
I am very impressed by this and by reflection, and the way Laravel uses it makes my heart burn—it's just beautiful. And I wish to fully understand that—the whole process—in general, and step by step.
Beginning from hitting the route to finally having, let's say, dd($x), where $x is from a method argument and is a TestClass that has another dependency of TestClass2 that should be constructed through: $x = new TestClass(new TestClass2());
I think those are beautiful mechanics and architecture, and understanding this is something I want so badly.
So again, my question is: how does reflection in Laravel actually work?
It's not about dd guys... Let's say without dd. Just as I said earlier - when we have this object instantiated from the class method. It's not about dumping it, it's just about having it from method injection by reflection.
The dd was only an example. It can even be die(var_dump()); and it will work
Laravel uses PHP's reflection API for several components. Of these, the inverson-of-control (IoC) dependency injection container and controller method injection are most visible to developers.
To more clearly illustrate the use of reflection, here's a dramatically simplified version of the routine Laravel's IoC container class uses to build up an object's dependencies through constructor injection:
function build($className)
{
$reflector = new ReflectionClass($className);
$constructor = $reflector->getConstructor();
foreach ($constructor->getParameters() as $dependency) {
$instances[] = build($dependency->getClass()->name);
}
return $reflector->newInstanceArgs($instances);
}
As we can see, the concept isn't too difficult to understand. The container uses PHP's ReflectionClass to find the names of the classes in an object's constructor, and then loops through each of these names recursively to create instances of each object in the dependency tree. With these instances, build() finally instantiates the original class and passes the dependencies as arguments to the constructor.
Controller method injection uses the same container functionality shown above to resolve instances of dependencies declared as method parameters, but there's a bit of extra logic needed to separate class dependencies from route parameters:
function dispatch(Route $route, Controller $controller, $methodName)
{
$routeParameters = $route->parametersWithoutNulls();
$method = new ReflectionMethod($controller, $methodName);
foreach ($method->getParameters() as $index => $parameter) {
$class = $parameter->getClass();
if ($class !== null) {
$instance = build($class->name);
array_splice($routeParameters, $index, 0, [ $instance ]);
}
}
$controller->callAction($methodName, $routeParameters);
}
Again, this adaptation is slimmed-down to highlight the role reflection plays and relies on our build() function shown previously. The ControllerDispatcher class uses the getParameters() method of PHP's ReflectionMethod to determine which parameters a controller method expects, and then loops through these to find parameters that represent dependencies that it can resolve from the container. Then, it splices each dependency it finds back into the array of route parameters that it passes back to the controller method defined for the route. See RouteDependencyResolverTrait for details.
If we ignore the application bootstrapping process, this dependency injection cascade typically starts for a request when Laravel maps a request to a route, and then determines which controller to pass the request to. Laravel first resolves an instance of the controller from the container, which builds out any constructor-injected dependencies. Then, Laravel finds the appropriate controller method and resolves any more dependencies for the arguments as needed.
As shown here, Laravel uses relatively simple techniques to implement these tools using reflection. However, unlike the examples shown in this answer, the framework adds a lot of additional code to make them as robust and flexible as they are today.
So I started working with a new framework called Zend Expressive which is the 2nd PSR-7 component based framework which should allow you to get code up and running fairly quick.
Now my problem with expressive is that as your project gets larger your factory boilerplate also increases. So for every Action class there's a ActionFactory class paired with it to inject the proper dependencies which we then create an alias to before we dispatch and pass that to our route.
The more action's the more factory boilerplate and I'm trying to figure out how do we cut down on that boiler plate?
As I said in the comments, I don't think there is a universal solution to create factories. I know that you don't use zend-servicemanager, but it comes with a cli command to generate factory classes: https://docs.zendframework.com/zend-servicemanager/console-tools/#generate-factory-for-class
It might give you ideas on how to create a factory generator yourself.
Here's an article about it: http://www.masterzendframework.com/simple-factory-generation-with-factorycreator/
Can try to implement logic with dependency resolver.
You can save a lot of factories by resolving dependency with class reflection.
$instance = null;
$reflection = new \ReflectionClass($className);
$constructor = $reflection->getConstructor();
if ($constructor === null) {
// no constructor specified, you can simply return the new instance.
$instance = $reflection->newInstanceWithoutConstructor();
} else {
// if there is constructor, you can loop through the constructor parameters and build the instance.
}
Need to be careful to avoid circular dependency here.
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
I am getting error:
GitHubApp::__construct() must be an instance of App\Project\Repositories\GitProviderRepository
I thought Laravel does some kind of magic when it come to __construct() so i don't have to inject it into new GitHubApp();?
use App\Project\Repositories\GitProviderRepository;
class GitHubApp
{
private $gitProviderRepository;
public function __construct(GitProviderRepository $gitProviderRepository)
{
$this->gitProviderRepository = $gitProviderRepository;
}
}
In other class:
return new GitHubApp();
When calling new GithubApp(), you relied on yourself to build the GithubApp instance, Laravel does not responsible for building that instance.
You have to let Laravel resolve the dependencies for you. There are numbers of way to achieve this:
Using App facade:
App::make(GithubApp::class);
Using app() helper method:
app(GithubApp::class);
Or using the resolve() helper method:
resolve(GithubApp::class);
Behind the scene, your class type and its dependencies will be resolved and instantiated by the Illuminate\Container\Container class (the parent class of Application). Specifically by the make() and build() methods.
Hope this help! :)
You can try as:
return app(GitHubApp::class);
or
return app()->make(GitHubApp::class)
It is done by the powerful IoC container of Laravel to resolve classes without any configuration.
When a type is not bound in the container, it will use PHP's Reflection facilities to inspect the class and read the constructor's type-hints. Using this information, the container can automatically build an instance of the class.
Docs
I have a custom framework where i have a class/method which uses my own Cache class.
Currently it is tightly coupled. So a method instantiates the Cache class like this:
public function someMethod ( )
{
$cache = new Cache\HHCache();
}
I want ro remove the tight coupling but that's actually where i'm a bit stuck.
I thought it would be a good idea to create some sort of ServiceProvider class. But i'm not sure if this is really the right approach.
To start i have HHConfig file which has a static property in which a cache class is defined. In short:
class HHConfig
{
static $_cacheClass = '\Core\Cache\HHCache';
}
So basically i have a class like this, which is part of the Core functionality of my framework:
interface IHHServiceProvider
{
public function getService ( );
}
Then i have another class which implements this interface.
class HHCacheProvider implements IHHServiceProvider
{
public static function getService ( )
{
$class = HHConfig::$_cacheClass;
return new $class();
}
}
So now someMethod can use the HHCacheProvider class to get an instance of a Cache class.
public function someMethod ( )
{
$cache = HHCacheProvider::getService ( );
}
My IHHServiceProvider isn't really like the typical Provider class since you can't really register any Services to it. It simply looks in the HHConfig class what "class" to load and returns in instance of that.
So somehow this method doesn't feel right to me, but i do think it shows what i want to achieve. In what ways can i improve this?
Please note that i'm not looking for a simple Dependency Injection pattern for this. Because i don't want to inject my Cache class to every constructors class. I need a non tight coupling way of getting an instance of the HHCache class somehow from within a method.
Some sort of provider class that can be part of my framework seems like the right direction.
Note: "provider" means nothing. There is not pattern by that name.
Instead of making some magical "privider", you should take a look at factory pattern. Basically the idea is a follows:
You inject a factory in classes that will use some services (assuming that Cache is not the only form of service that you aim for).
The class request from factory the service that it needs:
if service has been already initialized once, it just returns an instance to your
else it creates new instance, stores it and returns you to "consumer"
The simplest code example would be something like this:
class ServiceFactory
{
private $storage = [];
public function create( $name )
{
if ( false === array_key_exists( $name, $this->storage ))
{
$instance = new $name;
$this->storage[$name] = $instance;
}
return $this->storage[$name];
}
}
This is an extremely simplified example, but even in this case, if you inject an instance of this factory in any number of objects, they all will have access to same pool of instances.
If you ever decide to look into concept of DI Containers, then factories are also the place where it is appropriate to utilize them, without degrading them to as service locator anti-pattern.
.. and few lectures that you might find valuable:
The Clean Code Talks - Don't Look For Things!
The Clean Code Talks - Global State and Singletons
As per OP request
Especially since it will be part of the framework, you should inject the Cache. A DI Container is the best solution here, you can config the actually Cache implementation as a singleton. Your proposed solution is tightly coupled to some service and hard to test in isolation. Actually it looks more of a service locator pattern rather than provider.
If you're using a Factory that won't replace the DI Container. THe point of DI is that the code shouldn't be coupled to an outside static service. Unless you have a very good reason, any object should use only the injected (via constructor or as method argument) dependencies.