 So, we're going to start. So today I want to talk about dependency injection. As you will see in a minute, this is a very simple concept, very simple to understand. But this is probably very difficult to apply on your project. This is very difficult to know when and how to actually use dependency injection. So this session is going to be very technical. But I'm not going to dive too deep into the dependency injection container of Symphony. I won't take a lot of time just talking about dependency injection, what it is, how you can use it, what is a good idea, stuff like that. Which means that if you have any questions, any time, please interrupt me as a question. I want to be sure that everyone really understand what dependency injection is by the end of this session. This is a very important topic for Drupal 8, because everything is using dependency injection in Drupal 8, not everything, but a lot of things really. And if you are a developer, at some point, you're going to be using some kind of dependency injection. So dependency injection, this is a design pattern that is pretty well known. This is a very simple concept. It's kind of hard to explain, because as you will see in a minute, this is a stupid thing, really, really simple. But you need to understand how to use it to really understand all the benefits. So the first thing we need to talk about is we need to talk about a simple example that everyone can understand. So I'm going to talk about a web app with a user. And in many apps, you need to manage the user preferences, the credentials, user name, the long wait of the user, whatever. So we start with this very simple class, a user class. Of course, when I'm talking about dependency injection, I'm talking about object-oriented programming. So if you are not using objects, you can't really talk about dependency injection. So we have this user object with a language property. And we have a set language to be able to set the user language. We probably also have a getter, whatever, and a bunch of other methods. But that's not really interesting for what we are talking about. So this is a user class. And as this is a web app, we need a way to actually store this information from one request to the next one. HTTP being stateless, we need a way to store this information. And we can do that by using the PHP session storage. First, this is how you can use the class per easy. We create a new user. And we set the language to whatever we want. So this is a session storage class. Pretty easy. So basically, we have a set method. It takes a key and a value. And it uses the default PHP session mechanism to actually store the value into the session. And as you can see in the constructor, we are starting the session. And before, we are setting the session name, which is the cookie name that you're going to have in your browsers. And you can configure that cookie name, that session name, via the constructor. And there is a default value for it. OK, so now I have two different classes. The session storage one and the user one. And the user class needs a session storage to be able to serialize to store, to save its information in the session. One way to do that is by creating a session storage object in the user constructor, like this. So in the constructor, I create the session storage. And then in the set language, I'm storing the language in the session. Language being the key. And the language path to the method, the value, is enough. And using that is exactly the same as before. It's not more complex. I have two objects. But the user class is as it is before. I'm creating a user. And then I'm setting the language. I have no idea what's going on behind the scene. And I don't care, actually. I want to create a user. And I want to be able to set a language. Everything else is not that important from a user perspective, from a developer perspective. OK, so it is very easy to use. I don't need to understand the implementation details. But it's very hard to customize. It's very hard to customize because everything is outcoded here. If I want to change the session name, for instance, remember there is this argument for the session storage constructor, which is the session name, I can't. So very easy to use, very hard to customize. There is another way to do the exact same thing. Instead of creating the object in the constructor, I can also inject an instance of the session storage into the user constructor, like this. So now, if I want to use the user class, if I want to create an instance of the user class, it's a bit more difficult. So now it's very easy to customize, but it's slightly more difficult to use. Because before being able to create the user object, I need to create a session storage one so that I can inject it into the user. So more complex to use, but very easy to customize. And that's dependency injection. There is nothing more. End of the story. So dependency injection, big word, very easy to understand. Nothing fancy, really. So the difference is not really big, but it changes everything in the way you can interact with the object, in the way you can change things, in the way you can customize things. So I think dependency injection, OK, this is a design pattern, but it's more about being a best practice, really, that enables you to do a lot of different things. OK, so let's see and let's talk about all the benefits we have from injecting our dependency into our objects. So if I want to change, so I'm going to talk about the first example, the very first one. I'm going to explain why this is really bad. Even if it's much easier for the user, it's really bad for a bunch of reasons. So the first one, let's say that I want to change the session name, the cookie name. This is how I can do that with the first example. I can just hard-code the name here in the user class. Is it good enough? Probably not, because it is hard-coded here, so I can't configure it from the outside. There is no way to actually change this value. And of course, if I want to use the session storage for other objects, I will need to duplicate this value everywhere. So if I want to change the session name, I will need to change all the classes depending on the session storage. So whenever I'm creating a new session storage instance, I will need to change the value of the session name. That's not a big deal here. I'm talking about one, two classes and one argument. But if you think about having a much bigger app with tens of classes and tens of arguments, it's not really scalable. So this is not possible. There is one way to slightly improve things here. Instead of outcoding the session name here as a constructor argument, what I can do is I can create a global constant. It is much better. Much better because now I can configure. I can change the value of the session name from the outside. So it's not outcoded anymore into the user class. Is it better, really? Now, why? It's very difficult to test now. That's one thing that is really difficult because if you need to define a constant, it's global. So you can change the value by definition. So you can simulate how your user behaves depending on the value of this constant. It's not a big deal here, but you can probably find examples where you want to change the value and see how the user behaves depending on the value of this variable. So it's very hard to test, and this is global. So I want two different session storage with two different session name, whatever. It's not really possible. So it's a bit better because now we can configure things from the outside, but it's not enough. So the next step, and everything I'm talking about here, is people wanting to find a way to actually make this work without using dependence injection. And as you will see, you can find a lot of ways around dependence injection, but all those possibilities are actually very bad ideas. So that's why I want to talk about all these possibilities because at some point, you will think that this is a good option instead of injecting dependencies. It's never, ever the right choice. So now I can pass the session name as an argument for the user constructor. So it's better than before because now it's not global anymore. Now I'm passing the value from the outside so I can change it really easily so it's more testable. But still, it's not very good. Do you understand why? Sorry? Yeah, sure. But the biggest problem here is about separation of concerns. The session name has nothing to do with the user class. So here, I just have one argument to the constructor. But think about having more arguments in this constructor. Arguments for the user class and arguments for the session storage class. I'm going to have a mix of arguments. Some are for the user, some for the session storage. So the separation of concerns is really something important when you are thinking about how to create your classes. So it's better than before but not still good enough. OK. So one thing you can do, this is the next step really, is instead of passing one argument at a time, I can just pass a bunch of arguments for the session storage. So I have all my arguments for the user and then probably as the last argument, I'm passing an array with all the arguments for the session storage. That way, there is a clear difference between the arguments for the user and arguments for the session storage. So this is a bit better but still not enough because the separation of concerns, because again, you have outcoded some. We have added more complexity really. Now I need to create an array. I need to remember that the session name is named, the key is named. So I'm adding a bunch of complexity, which means that I'm going to need some clear documentation about how it works. It's not really clear. What is these storage options? What are the keys that I can actually pass? How it's going to be used by the session storage class? So it's a bunch of questions. I need to be able to answer really fast. So whenever you need to document something, there's a problem somewhere. The name is probably not a good one or the abstraction is too much, whatever. But there's a problem. So it's, again, better than a previous solution but not good enough. So if you use dependency injection, if you instead inject the storage, all those problems do not exist. You do not have any problem because you can do whatever you want by creating a new station storage object and passing the value here. It's from an argument from session storage. So the separation of concerns is really good. And I can do whatever I want, really. So that's why dependency injection is really something you want to use. And of course, using that, I can see some other problems. Let's say that now I want to store my sessions in MySQL or Memcached already, whatever. I can't because, again, I need to change my user class. And if you think about it, at some point, I'm thinking about moving to Memcached, and I'm changing the user class for that. Again, it's not simple. If I want to change something about the session storage, I need to change the session storage classes. I want to change the configuration of those session storage classes. I don't want to change all the classes depending on my session storage. And of course, if you are working on a very big project with many developers, if there is one team that is responsible for everything related to the sessions, they can do whatever they want if you are not depending on or if you are not archiving things into your design. So again, the team responsible for the user classes, they don't care about what you're doing with your session. But if you are using some outcoding names like the session storage class name here, then you have a tightly coupled class hierarchy. It's not good. You can't really work on two different aspects on your own. If you are using dependency injection, no big deal. You can change the session storage class name, no big deal. I don't care. Because at some point, someone is going to do the work of adding the glue between everything. And this team responsible for creating the glue is going to use the right class name and inject it into the user model. So instead of archiving the session storage dependency inside a user class, you need to inject it. I'm going to tell you that a bunch of times today, because it's so simple. But you need to really grasp why this is important. And smart people can do that. It's the next step. Instead of using dependency injection, you can think of using a global registry like that. This is a design pattern, so it must be really cool. It's really good to use. Actually, it's a very bad idea. So here, I have a registry. I'm setting the storage inside one key in the registry, which means that now in the constructor, I can get it from the registry. And if you think about it, it's exactly the same as dependency injection. In the sense that you can configure, you can change the session storage class name. You can do everything. But why? It's not a good idea. Yeah, sure. Again, we are adding yet another layer of abstraction. So we are just adding complexity for no benefits. I can't think about something that you can do with that that I can't do with dependency injection. But now we have a registry, which means that my user class now depends on another layer of abstraction. It's lower, less testable. It's not really easy to understand. And again, we have some hard-coded conventions between in the system. Because now I need to know that the session storage is stored into the session storage key in the registry. So this is, again, something that you need to document, that people need to understand. And if you want to change the session storage name in the registry, we need to change a bunch of other classes, unrelated to classes, really. So it's more complex than dependency injection, no benefits. So please, you can take a picture. Use dependency injection. It's really easy, and it solves many problems. The first version of this slide said it solves all your problems. I think it's more or less true. But actually, it solves many, many problems. So don't try to be smarter than dependency injection. It's not going to work. OK, so now, if I'm talking about dependency injection, so this is the second version of the class using dependency injection, you can configure things the way you want, really. So if you want to use a different session name, easy to do. If you want to use a session storage on memcache, easy to do, as well. And as you can see, the user class is exactly the same as before. It does not change anymore. If you want to test the user class and you don't want to use a session, because when you are using PHP unit on the command line, you don't have any session, so it doesn't make sense. So I need a specific implementation that, for instance, uses arrays instead of using session from PHP. That's something really also useful if the default implementation you are using is slow. If my session storage class actually makes an HTTP call to another service, for instance, in your unit test, you don't want to make HTTP calls. So you can just use this simple implementation that is really fast for your unit test. And of course, it would be even better if you use interfaces. So the next level is using interfaces. So right now, if you have a look at the class, the constructor take a storage argument. What is a storage? I have no idea. So you can actually inject whatever you want. You can inject a string, an object, a constant, an array, whatever. Of course, PHP is going to tell you that there is an error when executing the code, but it's too late. So using interfaces is going to solve a bunch of other problems. Not really related to dependency injection, but very useful still. So now I'm creating this session storage interface, a very simple one. It's just about getting stuff out of the storage or setting stuff in the storage. And now this is the final version of my class. Now I explicitly say that for my user to work, I need an instance of session storage interface. And I don't care about the implementation. I don't care if the sessions are stored in memcached, readys, or plain PHP sessions. That's not my concern. I just want something I can use to get value from and set value. That's all. Everything else is an implementation detail. I don't need to care about. I don't want to care about. That's very useful if you want to test your class, because now instead of creating a specific implementation of the session storage focused on testing, I can just ask PHP units to create a mock for this interface. And then I can say whenever I want to get this value, please return this or the value. Whenever I want to set a value, do whatever. So by mocking an interface, you can totally replace an implementation you don't care about. So when I'm testing the user class, I don't care about the details of the implementation of the session storage I'm going to use in production. I do care about how my user class behave when the session storage gives me this value or this other value, how my class behaves if the language is an anti-stream, for instance, or if this is not a valid language. I want to be able to test that. But how the session storage is actually going to store that information, I don't care. And my test, they do not care as well. So decoupling is also something that you have for free when using dependence injection. So dependence injection is really about clean code, which means reusable. I can reuse my session storage classes really easily. I have one interface, get set, that's all. I can reuse it whenever I need a session storage from one project to the next one. It's testable because I have this interface. It's pluggable. I can inject my session storage more than once in many different objects, which means that this object can actually be shared amongst a bunch of other objects. It's loosely coupled. So it's all about separation of concerns. So this is the definition of dependence injection from a Java container, actually. Dependency injection is where components, components being classes mostly, in PHP. So where components are given their dependencies, class instances, through their constructors, methods are directly into fields. So I've talked about how you can inject your dependency into constructors. But that's just one way to do dependency injection. You can also use setter injection. So instead of injecting my dependency into the constructor, I can create a setter, a method, that takes a storage, or directly into some properties. I don't like the last one. Actually, nobody does in PHP, probably because in a setter, I can't check things. I can't do a bunch of things. With a property, you can't really do anything. And actually, I checked Drupal 8. And property injection is not used anywhere in the core. So it's all about constructor injection or setter injection. So how do you choose between those two kind of injection? First, I think I really like constructor injection because your objects are usable right after creating them. If the storage is a required dependency for my user class, it's better to inject it into the constructor because whenever I create a user object, whenever I get a user object from someone, I know that the storage has been set. So I can use it right away. If not, I need to remember to actually set the dependency. So most of the time, you need to use constructor injection. So setter injection is great when you want to inject some optional dependency, for instance, a logger. And your class works without the logger. But if you inject a logger, it logs stuff. And setter injection is also useful when you have class A, depending on class B. And class B needs class A. So if you are using constructor injection, it doesn't work. So using a setter here, two setters, can break this circular reference. I'm not saying this is a good thing to do, but that's one way you can fix it. I think there is sometimes, but I think it's a bad smell. But anyway, if you have a lot of different arguments, so if the number of arguments is really huge, you can probably use setter injection for some of them. But again, I think it's bad smell. It means that your object is doing too much. So you probably need to create a bunch of other classes and separate things really. Any questions? Yeah. It's not really a bad practice, but in the PHP world, we like to have getters and setters because then you can easily change the implementation and what's going on in the getter or the setter, which you can't do with the property. So if you want to check that, I don't know. I have no idea really here. But actually, property injection is used in symphony. Sorry about that. So for very simple stuff. So for instance, in the HTTP foundation component, the request, when you want to access the query string or stuff from the request, we are doing that by using what we call parameter bags, parameter bag instances, and they are injected via properties. But it means it really makes refactoring difficult because you can't change anything, right? You just have a property. If you have methods, you can add a bunch of stuff in there. So that's why. Why not use language on struct for getter setter? What do you mean? We don't have it in PHP. Not yet. What do you mean? Yeah? Yeah, I think I can add a bunch of slides about trying to work around dependency injection a bit more. I mean, it adds complexity. underscore underscore set. If you are using that, that's probably bad smell as well. I mean, it means that then you don't have auto-completion anymore in IDs. You don't know what you can access or what you can't access. It means that you need to document things a lot. So that's a bunch of problems that happens just because you are using this kind of ugly abstraction, really. And the performance is really the same as using methods. So why not using methods then? Default. OK. So the question is, can we? So you are using dependency injection, but you want a default implementation if you don't inject anything. So basically, in two ways of, yeah. So here, I say storage equal null. So you can inject me a storage implementation, or if it is null, I'm creating a new one for you. Yeah? Yeah. That's something I can add as a bad practice, really. Yeah, because if this is a possibility, users are going to use that, obviously, always. So you're back to square one, really. Sometimes it makes sense. And if you have a look at Symphony, we have quite a few examples of that, but mainly for backward compatibility, right? Because at some point, we want yet another dependency. It was not the case in previous versions. So we make it optional, and we create a sensible default if you don't pass it. So if we are talking about backward compatibility, it can be useful. But from day one, probably not. Probably not. Yeah, factories, yeah. Sure, sure, sure. Factories, this is the exact same thing as the registry. It's yet another layer on top of simple objects. Last question, because I still have a bunch of slides, really. Would it be code smell to do both a constructor and a setter and getter, or a setter? Like, would that be bad to? Yeah, sure, sure. It would be OK to do that? It's OK, but you need a strong reason to do that. Well, you're allowing maybe someone else later on to overwrite the particular storage you've passed on the construction. And you're defining the class's construction, you know? Sure, the thing is, then, it's really out to understand what's going on behind the scene, because you created a user object with some kind of implementation. And then later on, for whatever reason, someone changed the implementation, and you don't understand what's going on. So not really comfortable with that. But sure, as you can see, I've talked about a bunch of things you can do to work around dependency injection and you guys have a bunch of other ideas, really. But at the end of the day, I think that trying to just use dependency injection, I know it's not fun. It's too easy, really, right? We are developers. We lack complex things that only us can understand, really. But sometimes, simplicity is really better than anything else. OK, so now let's talk about a slightly more complex example. Let's say that I'm creating a framework. I've done that a bunch of times, really. A very simple one just does one, two, three, four, five, six objects. So every time I create a new project based on this framework, I need to do this bootstrapping code, really. I need to create a request object. I need to create a response object. I need to create a storage, a user, some cache, the routing, whatever. But I don't want to copy and paste this code from one project to the next one. I want to abstract that. How can I do that? Pretty simple. Just create an application class. So now it's very easy to use again. For every single project, I can just create a new application and work with that object. Can you see a problem here? You're stuck with those classes now. Yeah. Basically, we are back to square one. We have all the problems we had before. I can't change the implementation. I can't configure my framework anymore. And you can imagine passing a config object, a config array, or whatever you can think of to work around this problem, all the things I've talked about, truly. But this is bad. So there must be a better way than doing that, right? And that's a dependency injection container. So I've been talking about dependency injection for half an hour. And this is the very first time I'm talking about a container. So dependency injection is totally different from a dependency injection container. You don't need a container to use dependency injection, right? Copy that a lot of times. And people often make confusion between dependency injection and using a container. It's two different things. They do not solve the same problem. A container is only useful if you have a bunch of objects that you want to manage in a standard way. That's all. So please use dependency injection now. And at some point, if you need a container, you can. It's not a requirement. So a container is something that you can use to describe your objects and their dependencies. It's also a way to instantiate those objects and to configure them. I'm going to talk about the on-demand part later on. So it's about being able to bootstrap your object graph somehow. So talking about our user and session storage, so in this design, we have two objects, user and session storage, one interface and two arguments, the session name and the session class. So a container is able to say, OK, if you want the user class, I know that user class depends on the session storage interface implementation. I have one session storage. And I know that this session storage class is going to be used because this is the value of the session name argument. And I need to inject a session name. And again, oh, sorry, it's mixed up, really, here. I have the name of the session to inject into the session storage. So the container knows everything about your classes, how they interact, and how to create those objects for you. The next slide is about a very simple example with Pimple. Pimple is a very simple dependency injection container. I wrote many years ago, really. And it's about 100 lines of code. So if you have time, please have a look at the code. You will see that creating a dependency injection container is not a huge amount of work. It's not all about magic everywhere. It can be really simple. And if you have a look at Pimple, have a look at Pimple version 1, not version 2. Version 1 was written for D-stock, actually, many years ago. It's a very simple example on how you can create a dependency injection container. Pimple version 2 is actually optimized for performance. And having a look at the code is probably more difficult. It's really complex to understand what's going on because everything has been optimized for performance. Whereas Pimple 1 was created for people to learn about what a container is and how you can implement one. But whatever the container is using, it's really about two different steps. The first one is about configuring the container, which means that above the gray line here, nothing happens. No objects are created. It's only about how to configure your object. So you are just configuring the container. Here, in Pimple, you are configuring the container via anonymous functions. That's one way to do that. It's not the way with Symphony. But that works pretty well. And as you can see, and then using the user is as simple as it can get. It's as simple as before when we were not using dependency injection. Here, I say, OK, I want the user from the container. And I don't care about how this user needs to be created. I don't care about the dependencies. I don't care about how you need to configure it. I just want to work with the user object. That's all. And as you can see, the user in the container is defined as an anonymous function. It creates a user. It injects the session storage. And the session storage is created. And we inject the session name. So I forgot to use the session class name here, but you get the ID. First step, we configure dependency injection container in various ways, really. This is just one example. And then we can use the container. Some rules, very important ones, actually. Objects must not be aware of the container. If you inject the container into your classes, it is the exact same thing as using a registry. You are adding complexity, because now you can't use your class without the container. So your object must not be aware of the container. There is some exceptions. In PHP, mostly for performance reasons. So if I want to create my user, by default, the container is going to inject my session storage. But let's say that I can do a bunch of things with my user object without using the session storage. And the session storage is really slow to create. In this case, you might want to lazy load or to lazy create the dependency. So injecting the container is one way to do that. You inject the container, which means that nothing is created. And the first time you need the session storage, you ask the container to create the dependency. But again, that's a bad smell, really. In the symphony dependency injection container that Drupal 8 is actually using, we have a feature that allows you to lazy load those dependencies via proxies. So it's built in. I'm not going to talk about that because it's too advanced. But that's a possibility you can do. So if your objects are not aware of the container, it means that a container is able to manage any PHP objects, any PHP classes. The only thing is that those classes must use dependency injection, of course. If not, there is no point. And if you have a look at Drupal version 8, you will see that the dependency injection configure all the symphony objects, all the Drupal ones, but also some Zen framework ones. And the Zen framework classes were not designed to work with the symphony dependency injection container. And that's not a problem because this is just about a bunch of classes with dependencies. And that's all. So the symphony dependency injection container is actually able to create those objects. So never inject a container into your object once more. And last but not least, because when you have a new toy, you want to play with it as much as possible. But it's not always a good idea. So a container does not manage all your objects far from it. A good rule of thumb is that a container manages global objects. And if you read symphony documentation, we are not talking about objects. We are talking about services. And a container, and I like to think about the symphony dependency injection container as being a service container. It's a way to manage all your global objects. I don't have some examples. So for instance, a database connection is a good example. It's a global object. Probably an object you need just one instance of. A logger. You just need one logger. It's different from a singleton. I'm not saying that you can only create one instant of it. But the dependency injection container is only going to create one. The first time you get the dependency, and then it's going to give you the same instance over and over again. Sorry? Everything is injected in symphony, really. So everything is using the dependency injection container. It means that everything is really decoupled. So it means, for instance, that in symphony we have a web profiler, which is a toolbar at the bottom of your website. It gives you a bunch of information about the number of requests you add, the SQL requests you add in your project, and a bunch of other things, really. We have the same version, the same classes, the same controllers, the same templates, work for symphony. They work for Selex, another framework. They also work for Duploit. So you're going to have the same web double toolbar we have with symphony. And for a bunch of other projects, just because we are using dependency injection everywhere. But a container does not manage your model objects. So a user, a product, a blog post, all the things that you can have many instances of. If you want to store a product and you want to store more than one product in the dependency injection container, that's probably a bad idea. It's not global. And again, most of the time, you don't need a container to use dependency injection. So I dived into Duploit code. And here are some examples on some services that you have in Duploit. So Duploit is using the symphony dependency injection container. And for the configuration, it uses YAML. So symphony can use XML, YAML, and plain PHP. And Duploit decided to use YAML. So this is a very simple example. You have a JSON serialization class. And here is how you can configure it from Duplo. So I'm just saying that it's an instance of this class. There is no dependency, no arguments, whatever. So if you want to get this serialization.json service, then symphony is going to create an instance of the JSON class without passing any arguments, probably because they are not. And from this description to the code that actually creates the object, we have a built pipeline somehow. We have a bunch of compiler passes, which means that in Duploit, you don't really read this file over and over again. It's just about the very first request, because then the container is dumped as a PHP file. It's compiled down to plain PHP. So this is what is actually created behind the scene. So as you can see, we return a new instance of the JSON object. And you can see that we are actually storing this instance somewhere, which means that the second time you want to get this service, you're going to have the exact same instance of this object. It's not going to create a new instance of this object. This is just one way of doing things. You can also ask a symphony to create a new object every time you get the service from the container, but there are exactly zero examples in Duploit and zero examples in symphony. So in practice, it does not exist really, because if you want a new instance every time, probably means that it's not a global object by definition, and probably means that it's not something that you want to store or you want to use the container for. A slightly more interesting example. So here I have a state. So the class is state. And it takes one argument. So this is an array. And here you see the at sign, at key value. This is a convention saying that I want the key value of the service to be injected here. So it means that the state class takes a key value argument, which is another service. And if we have a look at implementation, what is generated by symphony, you can see that we create a new object of state, and we inject. So we are getting the value, the instance of the key value. So in symphony, all the services have a name. And if you want to get a service, you need to know the name. And this is how you can do that. I mean, it's done automatically for you, actually. So we also have a way to configure things. So if you have a look at the first argument here, person something person, it means that we need to replace this with the value of this parameter. And this is not an object. Actually, this is an array. Sorry. Yeah. OK. So when you create an instance of an object, sometimes you need to configure it somehow. So you can use setter injections or whatever. So here, this is another example. The URL generator, you can use to generate a URL for any route in your Drupalite website. So there is a class. There are a bunch of arguments. Not all of them. There are a bunch really here. And you have calls, which means that what symphony is going to do is going to create the instance of the generator. And then it's going to call some methods on the new instance and then return the instance. And here, as you can see, there is a question mark. So this is at question mark, which is that this is an optional dependency. As you can see, we check that it actually exists before injecting it. Not going to dive too much into this today, but we have a bunch of documentation about that. We can also use factories. So here, we have a connection. And the connection is able to create a bunch of connections. And here, this is the default one. So we are using this getConnection static method on the database class. And we pass a default argument. And if you have a look at Drupalite, you will see that there are also ones with the exact same code, except the argument is different. So I have more than one connection. So I need to use a factory. And this is how it is actually generated. So we call this a funk, the static method, and we pass the argument. So there is another one, which is database, the slave, and the argument slave. So that's how you can have more than one object of the same class, for instance. You can also use other services. So here, this is the same as before. We are using a factory. But we are using another service to create my instances. So here, I'm getting a service, which is a factory. And then I'm calling a method on this factory that is going to create the object I want. Yeah? Nobody's lost? So here, I'm saying, OK, to create the cache.defaultService, this is an instance of the cache back end interface. So I don't know what kind of implementation I'm going to have. But for this default argument, the cache factory service is able to give you one by calling the get method, like this. So is that how you were able to pass an interface, which can't be instantiated because it's set in the factory? Exactly. Oh, by the way, the fact that we are still using class here means that when we generate the PHP code, we are also generating a bunch of PHP docs, which means that you're going to have auto-completion in IDs, like PHPStorm, NetBeans, and stuff like that. So that's why it's kind of important to actually have the right class here. You can put whatever you want. You can put foobar. But it's not that interesting for auto-completion. OK, you can have aliases. So it's just a way to link one service to another one. That's a great way, for instance. You have a bunch of different options. You have a bunch of storage, configuration storage. But the default one is going to be this one. So in the code, you want to use only this config.storage service. But behind the scene, it's really easy to change the implementation by just changing the alias. I'm running out of time here, really. So these slides are not really important. But you can also make some services private. It's not the case in Drupal, actually. But I think those should be private, which means that you can't get them. And that's pretty important because here, I really want the developers to use the config.storage service. And behind the scene, Drupal is going to use one of the many different ones. So saying public force means that you can't get those services. And actually, if you are doing that, I think a bunch of services should be private in Drupal, actually. Symphony is also able to optimize the container that is dumped as a plain PHP file. You're tired of me as well. There are so many things I can talk about, really. So this one abstract true means that this is something that the container of the trade is not really a service. This is just a pattern that you want to reuse a bunch of times. So it's abstract in the sense that you can't really get the service. But then you can say, OK, the logger factory, the parent is container thread. So it's going to actually import all the configuration here. So basically, it's going to call the set container here. So if you have a look at the implementation, it creates the logger channel factory. This is the class you have the first line. And because it inherits from container trade, it's called setContainer, and it injects the container itself. So in Drupal, there are many ways you can use the dependency injection container. So there is this Drupal class. Then you can say service and give the name and it returns the service you want. There are some shortcuts for some very important services. The last one is actually the same as the second one. But whenever you are using those methods, feel bad, right? Because it's not using dependency injection anymore. It's mostly for all the procedural code that is still in Drupal 8. So not everything is going to be migrated to objects. So at some point, you might need something, and you are not in an object. So you can't really inject the dependencies you need. Then you can use this. But if you are using this in a class, that's a no-go, really. So at some point, someone need to bootstrap the container. At some point, someone need to say Drupal service something. If not, it's not going to work. So that's done by Drupal kernel boot. And that's where the container is actually created. That's where it is dumped as a plain PHP file. And that's where we get the kernel and we under a request. So if you want to learn more about how it works behind the scene, you can have a look at the boot method of Drupal kernel. OK, I'm not going to talk about that. So some advanced topics have not talked about compiler classes, tags, lazy services. That's really advanced topics. You don't really need to dig into now if you're not familiar with dependency injection in the container. We have plenty of documentation. So there's just a link where you can go to get more information about that. And I think that's all for today. Thank you. Thank you. All day, every day. Yeah. Have you heard all the lights?