 Wait for five more minutes or should we start? We start in like five minutes, but we are all set. Well, this generally does not happen that we are all set just before time. So we'll still give it three minutes and then start. OK, let's use this couple of minutes and maybe we'll discuss something or we get a time to get one more extra question at the end. OK, so hello and welcome everyone. We are talking today about PHP design patterns, PHP 8, and how it all affects Drupal Core. So before starting an introduction, my name is Ajit Shinde. I'm from India. I work as a senior developer for Chepers. And these are my Twitter and Drupal.org handles. Hi, this is Piyush. I work as the practice lead for Drupal with QED42. I mean, is everyone here comfortable with Drupal 7, first of all? I mean, has everyone seen Drupal 7? Yeah, I mean, with Drupal 7, everything was procedural. All of us know that, right? Right from your index.php file which bootstrapped or which was the entry point for Drupal and then a set of bootstrap functions getting called, right? So this is how your index.php file looked in Drupal 7, its own menu execute active handler, which was the entry point for any menu route. I mean, I'll call this as route since I'm doing more Drupal 8 now. But yeah, this was the entry point for all menus. And then the control was getting passed to the menu callbacks via the different set of procedural functions, right? The only way to extend Drupal 7 was using hooks, right? And how many of you faced issues or difficulties or trouble understanding what are hooks? Very few, very few. And how many of you started with Drupal 7? OK, that explains it why. Because I started with Drupal 7 and I was right out from my college doing Java programming back in the college, doing a lot of object-oriented programming stuff there. But suddenly, I was introduced to Drupal during my internship for the very first time. It's a PHP-based framework. That's all I knew about it. And then there are certain XYZ best practices to do certain things in Drupal. And then the only way to extend something, you can't hack the core. It's something that I was told on my first day. You can't hack a contract module. That is something that I was told on the first day. The only way to do something or extend something was using hooks. I was like, what the hell is hook? It's a hook. And then it took me a lot of time to get hang of what hooks are, how they're getting invoked, where they're getting invoked, how do you define a new hook. Very different from a typical object-oriented background, which I was coming from. The example that we've taken here is from links module, where in the module tries to define a formatter, how the settings form for it looks like, and how the view for it would look like. But yeah, all of it was really difficult for me to digest in. And this is what the basic challenge with Drupal 7 was, actually. Where in onboarding new folks to Drupal was really difficult. And since Drupal has its own way of doing things, the Drupalism baked into it, it was more difficult for Drupal to also adopt something which is standard across different frameworks which are being used. And that's where Drupal 8 came into picture. The new and the shiny thing, all of us. But Drupal 8, so at Q8042, what we also do is every year we have bootcamps, which is responsible for training new folks with Drupal. These fresh folks who are coming out of college. We saw a drastic difference or delta in terms of how people were getting acquainted with Drupal 7 versus Drupal 8. Now, for us, it was more tricky to explain them what hooks are or how do you overwrite certain things. Because people would usually come back and ask, why don't I create a separate, create a different class, extend it, and overwrite the core functionality with Drupal 7. But with Drupal 8, those questions were no longer there. It was much easier for people to ingest what's there and how it has been developed. And comparing the index.phd file, which is still the entry point for Drupal 8 Plus, you can see there are a lot of objects and classes being used here. The menu execute active handler, which was there in Drupal 7 for routing, has been replaced by HTTP kernel. And that is taken from Symphony, actually, from a framework which is outside of Drupal. And this very clearly explains how Drupal moved from the not invented here syndrome to accept everything, which is a standard. And implement it within itself rather than re-invending the wheel. With this, with object-oriented programming coming to picture, hooks are not the only ways in which you can extend the Drupal core functionality, but rather it brought in more and more ways of writing code as well as extending what's there in Drupal core. For example, hooks are still there, by the way. It's going to take some time to go away, but it would soon be replaced with events. There's a plugin system which allows you to create new pluggable components which would work the same way a base framework has been set up within Drupal. For example, your block system is a very good example of plugin system wherein you can go ahead and create new block plugins. And they all would behave in the same way as your block system is supposed to operate. You have event and event subscribers. One of the other interesting things that happened with Drupal 8 is not just a consumer of external libraries or standard libraries, but Drupal can also produce PHP libraries. For example, while writing a contract or a custom module, you can go ahead and write a new PHP library and make it available to the outside world via Composer package. And many more. Now, since object-oriented programming has come in and there are a number of ways of doing the same thing, it's also important that there are certain standards which get followed while solving certain problem statements. And that's where design patterns come into picture. I'll let Ajit talk more about it in depth. OK. So this is sort of the Wikipedia definition of design patterns. And it's basically very generic. It applies to not just PHP but for other frameworks. But let's not go into much details about it. Let's understand it in a simpler way. It's just a way in which you could write better code or a better way to write code, which makes it easy to understand and maintain. These are some of the design patterns that we will be discussing today. And for discussing that, let's consider a very simple scenario of a car manufacturing unit. And just for the sake of example, consider these two. One is the car and one is the engine. The engine cannot drive without the car. But they are still separate. Just keep this in mind and let's talk about how we can implement this scenario in different design patterns. The first one is dependency injection. It just makes managing dependencies very easy. And a way in which you could think about it is let's say there is a class A and there is a class B. Class A uses some of the methods of class B. So B sort of becomes a dependency for A. Some functionality of A is not complete without B. So B becomes automatically a dependency for class A. And to map our example into PHP, we consider two things, two real-life objects. One is car and one is engine. So an engine class would look like this. So it might have a type. It might have a cylinder. It might have an fuel. And just for the sake of this slide, there's just a speed on or accelerate. The way you create an object of engine is on the right just with the new keyword and then call the method on it. And the way car is created is, again, with a class, because we are doing object-oriented programming. So there's a car type, which could be Hatchback, Cidan, or SUV. There is an engine, because a car definitely needs an engine, and there is an accelerate function, just for example. And as you can see, because the car needs engine, the engine is created here while the car is created. Like, can anyone point out a problem with this? Like, what's the problem? Yes? Yes, please. Can you switch the engine? Yeah, we can't switch the engine because it's hard-coded. Like, we cannot have a manufacturing unit of a car that produces only cars with four-stroke engine and diesel fuel type. How can this be solved? Like, how can you solve this? Like, we don't want to hard-code. So a possible way could be to sort of provide those as arguments as well. So when creating a car, you could then specify the engine type and then provide the cylinder and then fuel, basically. So but there's still a problem with this. Can anyone point this out? OK, so yeah. So engine becomes sort of a hard dependency. And engine cannot itself be extended as we require. And it's generally the case that you don't go start manufacturing an engine when you start manufacturing a car. Engine is manufactured way ahead before starting to build a car, which makes it easy. Which makes it easy to test the engine before and separately before putting it into the car. So that's the benefit. And in this way, the engine is more testable if we created separately. And how dependency injection sort of solves this problem is to create an engine separately and pass it as an object while creating the car. So the engine is created separately. You can see the engine is created on the right side bottom, like with the new keyword. And it is passed as an argument to the car, like the second argument. And it is received in the constructor here and then initialized. So the benefit of this is it sort of becomes loosely coupled, both the car and the engine. It becomes very easy to test engine separately and a car separately, because you create a car separately from the engine. But this is like a very simple application. In the real world, it's very complex. Like a car engine in itself could be created with different parts. And this is one of the parts. It's piston. There are other parts of engine, like crankshaft and other things as well. And in turn, a piston itself is created by so many parts. And all of these parts sort of are created separately and then brought together, create a piston and then depending on the type of cylinders, the engine is created. So the point is the engine is the problem is complicated. And a way in which the, I'm sorry for this, and the way in which these dependencies are managed, if you have to manage it by yourself, it becomes very hard. Because then you have to create a class for a piston. You have to create a class for a piston crown, and then so on and so forth. And then pass it and inject dependencies. And it becomes like a multi-level thing. So the modern frameworks like Drupal do it for you. Like they provide a way in which these dependencies are solved automatically by dependency injection container. So, and this is sort of an example of a link formatter again from a link module, but this is Drupal 8. And all in a way, link module is different from the field or a normal text module is it needs to validate the path. Like it needs to validate the link. So it has sort of a dependency on this. I'm not sure if it is visible, but there's a dependency for the path validator at the bottom. And it gets passed using this function, which is responsible for creation of plugins. And this container provides this service, and it becomes part of the path validator method. Which is a protected value inside the class itself. The way dependency injection is managed in service, because one service can depend on a different service, is using services.yml file. This is sort of, yeah, this is one of the modules that I maintain, auto logout, automated logout. What it does is it automatically logs out user if they are not active for some time. And there is this auto logout manager. Thank you. Auto logout manager that again does a lot of things, like it requires all of these other services. So we just pass them on in the services.yml as the name of this. And they become automatically passed into the same order in the constructor. And then you can use them. So these are the couple of ways in which dependency injection is done in Rupal Core. The next pattern is sort of an adapter. And it sort of humorously fits in the problem we just had. So this was a problem. This was an image shared by some kind community member in the Drupal Slack channel in DrupalCon, which they asked you to bring these adapter when you're traveling to DrupalCon. But my country does not produce those. So what we have is sort of a universal adapter, which acts as a middle layer between the adapter required by Prague and the adapter created by my country. And it sort of acts as a middle layer and lets the system work. And in our scenario, let's say, now we have sort of electric vehicles. And you can see that nothing burns like there is no fuel. And the electric engines are basically completely different than a traditional internal combustion engine. And since our expertise is building engines and cars, we are not an expert of creating electric battery. What do we do in that case? In this case, we sort of purchase it from someone who is an expert in that. So consider this as a class that we are getting. So it's called like a third-party electric engine. And since it is controlled completely by a third-party, we don't have control over its methods. So it does not have an ignition like our system has. It does not speed on or ignition off is not present. But it's turned on because it's an electric thing. It does not ignite. It turns on. So this sort of makes it incompatible, very similar to the adapter situation. So one different system here, other different system here. So what do we do? We introduce an adapter in between. And that adapter comes in format of a class. You can see it here. The adapter still implements our interface. So sort of the interface that is compatible with our system. So the adapter becomes compatible. And you can see that we sort of get a third-party engine like we purchase it on the right-hand side. We purchase a third-party engine. We have, let's say, 800 cell battery type. And then we sort of pass this as a dependency inside our adapter, basically. So we have an adapter and pass our third-party engine as a dependency injection. And receive it here and then engine. And so you can see that the methods implemented by the adapter are all from the interface. It has ignition. It has speed on. It has ignition off. And this calls in the methods inside it, basically calls the method of the external engine which is like turn on, acceleration, and turn off. Does anyone have any question? Is it clear? Can I go ahead? Okay. So the way in which it sort of is implemented in Drupal. They're not very good examples in Drupal Core. So I borrowed this one from a contrib module called S3FS. It integrates Drupal's file system with the S3 file system from Amazon. So what it does is, you can see on the left-hand side, there is a service inside this S3FS module. What it does is it imports the libraries from AWS. You can see the namespaces as, like all as the AWS namespaces. And in the library, in the service, there is a method called as getAmazonClient. And towards the end, it creates a new S3Client. So you can see that the object is created of a class that is not provided by Drupal, but a third-party library provided by AWS. So this method will return an AWS object to Drupal. And the reason for writing this adapter is very simple. It's like, let's say AWS comes up with a new API. And the new API is not backwards compatible in which the way you create this S3Client, it intakes an array, but some parameters of the array or some keys of array have changed. So all we need to do then is to modify this adapter and adjust the client config. And we just do it at one place. And in our Drupal system, we do not use this AWS class directly, but we always use the adapter. And that is how it makes it easier to maintain. So whatever change the third-party has, you only need to change it at one place and it becomes more maintainable. Any questions? Okay. So this one is sort of easy. So the observer reaction or design pattern is just as the name says it, it's to observe and react. And this was sort of an example that I found. So there is this piece of code doing its own thing in its own state. Maybe some doing something with the database or sending out an email. So whatever state it is. And you can see that the other pieces of code, it just are independently observing it, like what state it is in. And they may choose to react or not react. They may observe it differently. You can see that someone has binoculars, someone, I don't know what it's called. And someone chooses not to react at all. It all depends on the state the application in. This is like an observer pattern in like layman terms. And before showing you the code, let's say our car manufacturer wants to make the cars very safe. So in this case, what we have to do is introduce some safety features to the car. Like the car needs a seatbelt, the car needs airbags. There needs to be some warning systems. And for the sake of simplicity, we consider this example of having a warning displayed to you when you reach a certain speed and you did not, like you, the driver missed to put on the seatbelt. It's very simple. Some car does that. Maybe with a beep warning, my car announces it in a certain way. So how do we implement it? So the problem is or the challenge is to warn the user if they reach a certain speed but they did miss to put on the seatbelt. So how do we do it? So basically you can see that. So there are two things. One is there is no seatbelt and a condition where you reach some speed and then the system reacting differently. And that's what the accelerate function does. It gets the current speed and if let's say the speed is greater than 10 and there is no seatbelt, it sort of triggers an event and like dispatches it. And in short, what it does is it creates an object of this. You can see the object of safety event and provides an event of no seatbelt. So basically just and dispatches it. And there is a subscriber that sort of listens or there are like listeners who listen to the state of the object, state of the code. And they have sort of we have written this get safety events as a sort of a public method. And in case of no seatbelt, we just sort of do warn seatbelt, warn no seatbelt. This is the name of the function it calls. And then it is displayed. You can pass in more parameters and more functions. So it could sort of do behave differently. Like there could be like I said, beeping some warning displayed on the dashboard. Some car manufacturers may even choose to slow down the car. Like they would not let you go past a certain speed. So and there could be other events as well. This is just example of one event. But this is what observer pattern is. So basically two, there is an event and there is a reaction to that event. So event and event subscriber. The way it is implemented in Drupal and this is in core is, and this is an example of the CK Editor module. And what CK Editor module configuration provides if you are aware, some of you are aware, you can pass in custom CSS like custom CSS which becomes part of the editor. And because you can configure CSS in the configuration form itself, we need to invalidate some cache. So the libraries, the CSS libraries sort of need to be invalidated. So you can see that in get subscribed events, whenever a config is saved, you can, you just call an on save. So on save method is called and the cache tags are invalidated. So this is sort of the observer pattern implemented using event subscribers in Drupal 8, 8 plus. So this sort of completes the design patterns and going into the benefits and have sort of made this, like shared some of the benefits as we speak about it. But you can use like better use of the object oriented principles. And these are pretty standard, even if you talk about dependency injection with the person in a Java framework, in a .NET framework, they would still understand it. So, and the problem PUSH was talking about onboarding people from outside into Drupal, it becomes easy because you use common terms, common vocabulary, the code becomes maintainable. And as we saw, it becomes testable because components are very loosely, loosely coupled. And the integration between the third party systems, like symphony or CK editor, it becomes a little easy because those like symphony heavily realize, implements the best standards and everything. And talking about implementation of best standards, best PHP standards, and by the third party libraries used by Drupal core, let's move on to the next topic, which is like a final topic of the session, which is like PHP 8 and how it affects Drupal core. Right, thanks Ajith. So, so far what we've seen is Drupal 8 and 8 plus has brought in object oriented programming with PHP and taken in certain components from symphony as well as certain other standard PHP libraries into its core, right? Now, it becomes more and more important for Drupal to stay up to date with what PHP versions are getting released because you're dealing with certain dependencies which might be dependent on different PHP versions, they might upgrade themselves and Drupal might not be able to upgrade itself because the bare minimum PHP requirement for let's say a plugin is PHP 8.1, while for Drupal it stays 7.3, right? You can't upgrade that package within Drupal core because your Drupal core is not compatible with latest version of PHP, right? So this becomes more and more important is what I would say, that's one part of it. Secondly, with newer versions of PHP, there are newer features which are coming in, there are newer RFCs which are getting implemented, right? To be able to leverage those, your Drupal core needs to be more compatible with newer PHP versions, right? What we're going to do here is take a look at a few PHP 8 features, how Drupal 8 is, sorry, how Drupal 10 is, or what changes Drupal 10 is making in its core to make itself compatible and be ready with PHP 8.2 which is gonna be released in November, but still the efforts that we're trying to make here, right? So this is one of the first one which is named arguments. I mean, all of us would have written functions, they would have had arguments within them, but has anyone run into a situation wherein you were parsing the function, when calling the function, you were parsing the arguments in a different order? That was right, and then you see an error, if it's type ended properly, you see an early error, if it's not type ended, you see an error pretty late in the cycle, right? With PHP 8, you don't really need to worry about it anymore. So what we have with PHP 8 is, you have named arguments, which means that while calling a function, you pass it in a key value pair which says that the value that you're passing in maps with this argument, right? So if you look at this example, we have a function foo which takes in four different arguments, A, B, C, D, and while we're invoking this function, we are parsing the arguments in a different order, right? But it's keyed with the parameter name, right? So you no longer need to worry about it. Along with that, there's a sugary syntax there wherein you see there's a question mark before string, right? Where in PHP 8, you could go ahead and say that this type of, I mean the argument type can be of this type or it could be null, right? And there are a lot of other syntactical changes, but we're not gonna cover all of them in this session, but we'll try to go through a few while they come across in the examples. Deprecated dynamic properties. So how many of you have created an object of a class and then defined a dynamic property on top of it? By dynamic property, I mean a property which has not declared in the class itself. So for example, I have a class A which has two different properties, B and C, right? Now I've instantiated an object of class A and I do dollar A, arrow operator D is equals to 10. I think a lot of us would have done that, right? The examples of this in Drupal Core as well, but with PHP 8, there's a deprecation warning that you will start running into which would say that you're not allowed to define a dynamic property on an object anymore, right? Let's take a look at an example from Drupal Core. So this is your config entity-based class. All of us would have seen the specific statement wherein we copy the original entity object before saving and it's available with the original key, right? Here original is a dynamic property on your entity object which is not declared in your entity-based class, right? And if it stays in Drupal Core and we ship, Drupal 10 is released and we're running Drupal 10 on PHP 8.2, our logs would be full of certain, full of warnings, deprecation warning, saying that this is no longer supported. Now the solution to this is, since this is a deprecation, it's gonna be completely unsupported with PHP 9. Since this is a deprecation, PHP also gives you a way to make it backward compatible by allowing you to have attributes. Now, what do you see in the patch on the right? There's an attribute added in a certain format which is quite new, I would say. How many of you have seen this syntax? Okay, quite a few, great. So we'll discuss about what it is in the next slide as well. But yeah, this is an attribute which allows you to say that basically, I'm gonna allow dynamic properties on this class, right? And does the patch apply to config entity base to support it with Drupal 10? And here's a link to the meta issue which talks about how and where these dynamic properties are being handled. There's another one which is in discussion, using weak maps for container serialization problem. So with Drupal 8, all of the service objects which we were creating or instantiating, right? They had a dynamic attribute called as underscore service ID. Now, this service ID was leaking across different service definitions, leading to bad garbage collection, I would say, right? Because even if an object is no longer referenced, it was still in the memory because your service ID has leaked up across multiple service definitions, right? Well, the solution to this has been done, has been brought in Drupal 9.5.x wherein we started using special object storage wherein every service instantiation is also followed with creating a hash map of the object so that you have a unique ID in your unique ID for pointing to every service object, right? And this allows you to also do the garbage collection better wherein these unique IDs will be garbage collected once they're not referenced anymore. Proposition for 10.x is to use weak maps. Now, the only difference between, or the basic difference between special object storage and weak maps is special object storage stores your hard links, whereas hard references wherein weak maps store weak references, which means that weak maps would do a garbage collection on its own. Weak map would go ahead and check that if an object is no longer referenced by a piece of the code, go ahead and remove it from the memory, right? Also, weak maps allows you to have objects as keys, which means you don't have to create a different hash of the object. Rather, you can have your entire object as the key for the map. So this is a new data type introduced with PHP 8 and there's a discussion and more details on this available on this issue queue. Now, coming back to attributes, one of the attributes that we saw previously was to allow dynamic properties on classes, but attributes are a replacement of annotations, I would say. So everyone must have seen when you're defining plugins, you write certain annotations in your dog block, which requires a dog train annotation plugin to be able to parse it and store the metadata within Drupal, right? With PHP 8, now with PHP 8, attributes have come into picture instead of annotations for defining it, which means you would no longer need a dog train annotations library to parse the annotations. Rather, you could have the metadata getting parsed by PHP core itself, right? Now, Drush has already started implementing it, which means that your Drush command files would no longer require you to define your options, help, usage, arguments, et cetera in annotations. Rather, you could use attributes to define them. So Drush has already adopted, I think it might sooner or later start getting adopted in Drupal core as well. Now, one of the basic ones which is defining type hints. So whenever, wherever possible, there's a policy for this as well on Drupal core, on Drupal.org, which talks about define type hints wherever possible, right? Because what type hints allow us to do is, number one, have early warnings in the code bay, in your application execution, right? So everyone must be familiar with this way of declaring a property on a class, right? Now, this can change to the one that you see on the right, which is more condensed, and you could define, you could type into your properties, and you no longer would also require to provide another dog block for saying what type of property this variable is, right? Same thing for return types on functions, and the policy draft for Drupal 10 is right here on the link below. Now, you may already know Drupal 10 is gonna require PHP 8.1, right? Because Drupal 10 would require symphony 6.1, which basically depends on PHP 8.1. At the same time, Drupal 10 will be compatible with PHP 8.2. Now, PHP 8.2 is supposed to be released in November 22, but there are already efforts being made to make it compatible, right? What this means for us is we will have larger support lifetime for Drupal 10 because we're already on the latest version of PHP, and other dependencies might, I mean, other depend, it would be much easier for us to say that Drupal 10 will have a longer lifetime with these dependencies as well, which Drupal code depends on, right? We have newer ways of writing more robust code, right? Typepins everywhere, and with upgrade to Drupal 10, you should make a consideration of upgrading to PHP 8.1 as well. Now, the community has already made a lot of efforts enlisting down what are the hosting and distribution support and timelines for supporting PHP 8.1, for certain hosting platforms, which is available on the link below. But yeah, I think that's all it's gonna take us to move to Drupal 10 and have it compatible with PHP 8.2, right? I would close the session with this notion that Drupal 8, Drupal 10 is gonna be compatible with PHP 8.2. It's gonna take some efforts, and I think it's gonna take efforts from all of us to contribute back and make sure that Contrib is compatible with PHP 8 as well, like the deprecation warnings or dynamic attributes problem which we are seeing, right? It has to be handled across Contrib as well, right? With this, I'll open the floor for questions. Any questions, guys? We do have time, right? Okay. Any coverage on? Do you know what the plans are about using the new constructors in PHP 8 to define the properties within a class? Do you mean property promotion with constructors? Yes. I think the idea to support PHP 8.2 at this stage is to make Drupal as much as compatible as possible, and then the next steps would be to bring in the goodies that are coming with PHP 8 into Drupal 10. In the case, thank you so much. All right, thank you guys, have a good day. Please consider filling the session survey. Thank you.