تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

مرور آیا کانتینر سرویس بیش از حد است؟0:00

(upbeat music) Laravel's service container gets accused of being over-engineered, that it's too complex, it's too magical, there's too much machinery for one of mouse to just creating objects. But no, that's not true at all. (whooshing) If you've ever worked with dependency injection containers before, this criticism kind of makes sense

injection containers before, this criticism kind of makes sense because Laravel's container does a lot automatically, it resolves dependencies, manages singletons, and handles contextual binding. So from the outside, it looks like an elaborate infrastructure for something that should be simple, but the container follows explicit deterministic rules. Every resolution is traceable and the complexity is opt-in. You can use Laravel for years

Automatic Resolution0:47

Every resolution is traceable and the complexity is opt-in. You can use Laravel for years with just automatic resolution and never touch the advanced features. And let's start with automatic resolution. So I have a payment gateway for Stripe that issues a charge and I want to log those charges. So we of course need a constructor here, but I want to log this using a particular logger. I have a file logger that I want to use,

but I want to log this using a particular logger. I have a file logger that I want to use, which as this name implies, is something that's going to log to a file on the file system. So this will give me a logger that I can then use inside of this charge method. So that's, we could just log and slog that a charge was made. And voila, we don't have to worry about anything. Well, we have to worry that our code is going to work,

And voila, we don't have to worry about anything. Well, we have to worry that our code is going to work, but as far as getting this file logger to the Stripe gateway, we don't have to worry about that. There's no configuration, no service provider registration. We just type in, we say that we want this file logger and the container is going to read this constructor signature. Use reflection to provide this file logger to my class. But the cool thing about the container is that,

Use reflection to provide this file logger to my class. But the cool thing about the container is that, you know, it's going to do this automatically for just about everything. So let's look at the file logger. Now this doesn't need any dependencies, but if it did, you know, all we would have to do is type in it in the constructor, and then the container will provide that dependency there. So we can nest these dependencies, however much we want,

and then the container will provide that dependency there. So we can nest these dependencies, however much we want, because the container is always there, using reflection to look at the constructor signatures, and it's providing the dependencies that all of those need. But of course, there are times when we need something more than just, you know, a concrete class, maybe we want to abstract this file logger so that it implements logger, which it already does. In which case, I would say that's okay,

Binding Interfaces2:50

so that it implements logger, which it already does. In which case, I would say that's okay, I want a logger here. But of course, logger is not a class. It is an interface. So we can't just create an object based upon an interface. So what we need to do is register a binding with the container. We do that inside of app service provider and inside of the register method,

We do that inside of app service provider and inside of the register method, we essentially want to tell our application that we want to bind the logger interface with the file logger class. So that now, any time that the container sees a class that needs the logger, it's going to always provide the file logger there. So that's fantastic, because what if we ever needed to swap out a different logger

So that's fantastic, because what if we ever needed to swap out a different logger like for testing or something like that? Well, we can do that, because now our code is set up to work with abstractions. And of course, this is where the container's value becomes very obvious, because our gateway here doesn't care about what kind of logger that it uses, it just needs a logger.

about what kind of logger that it uses, it just needs a logger. So we could swap this out at any time, not just for testing, but all we would have to do is go to the app service provider, change our concrete class here, and then there's no other code changes that are needed, because our payment gateway is using an abstraction, as opposed to a concrete class. But the service container can do more than just that,

Managing Singletons4:21

as opposed to a concrete class. But the service container can do more than just that, it can also manage singletons. Let's go back to our app service provider, and let's say that we have an API client that needs to be the same instance across our entire application. So what we could do is bind or no, we don't bind, we set up a singleton, and then we pass in the class that we want to use.

we set up a singleton, and then we pass in the class that we want to use. In this case, I have an API client. So that's now, no matter where I use this API client, if I do it inside of a route, let's say that, let's just pick one, the facade test here, we could use the API client, and this would give us an instance here,

we could use the API client, and this would give us an instance here, but if we needed to use that same client elsewhere, well, all we have to do is for this facade trace, we could use the API client here, and it doesn't matter, between both of these routes, it's going to use the same instance of that API client, because we set it up as a singleton, so therefore the service container

because we set it up as a singleton, so therefore the service container is going to treat it and manage it as a singleton. So let me put something in the code, so that this just doesn't appear there. So we can say that the client is the same as in facade test. We'll copy that, so that we can essentially do the same thing here, except we need facade trace there.

Contextual Binding5:45

so that we can essentially do the same thing here, except we need facade trace there. So it's a singleton, it's going to be the same instance everywhere that we need to use that API client. But now we get to look at contextual binding, and this is probably the most advanced use of the container, and it's where most developers realize the real power of the container, because we can set it up so that certain classes

the real power of the container, because we can set it up so that certain classes receive different implementations of the same interface. So we have this stripe gateway here, but let's go to the post controller, and let's say that's okay, I want to use a database logger for the post controller, in which case we would need the constructor here, and we'll have a public logger, and we'll just call it logger,

and we'll have a public logger, and we'll just call it logger, just like we did before. Now we've currently set up a binding, so that, well, I close the file. Let's go back to app service provider, we have a binding, so that every time that we use the logger interface, the container is going to supply a file logger. Well, I don't really have another logger,

the container is going to supply a file logger. Well, I don't really have another logger, let's create one right quick. In fact, let's just copy the file logger, we'll rename it to database logger. And of course, we need to change the name here, database logger, implement logger, that's going to be fine. As far as the log method is concerned, we aren't going to do anything there,

As far as the log method is concerned, we aren't going to do anything there, except write to the database. All right, so we have this database logger, and we want to use it inside of the post controller, but we want to use the file logger for the stripe gateway. So back inside of our service provider, let's change this, so that instead of using the bind method, we will use the win method, and we'll tell it to win, it's the stripe gateway,

we will use the win method, and we'll tell it to win, it's the stripe gateway, then it needs a logger instance, and we are going to give it the file logger, just like that. But if it's our post controller, which all we have to do is change the concrete class here, so that it's post controller, and it needs a logger, then we want to give it the database logger. And so this way we can use both logger classes in two completely different parts of the application,

And so this way we can use both logger classes in two completely different parts of the application, and the service container is going to handle it for us, so that we don't have to worry about it, and that is awesome. So the service container isn't over-engineered, it's just a sophisticated part of the infrastructure, and the great thing is you don't have to know how it works to start with, because you can use automatic resolution for years and never configure any kind of binding,

to start with, because you can use automatic resolution for years and never configure any kind of binding, it just works, and as your application grows, then the machinery is already there to handle whatever your needs are, whether if you need to swap implementations, manage singletons, or handle contextual dependencies. (scraping)

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟