PHP Interfaces & Polymorphism - Interfaces Explained - Full PHP 8 Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
interface is like a contract that defines all the necessary actions or methods that an object must have let's look at the interface using a non-technical example first let's say that someone owes you money and you want to collect that debt your first step would be to try and collect that debt yourself but then if you're unsuccessful you will probably hire the collections agency or some kind of company who would collect that debt for you for some kind of fee or commission now when you hire a debt collector you don't care how they actually collect the money all you care about is that you get your money or some portion of your money there can be multiple debt collectors each one having their own methods or ways of collecting the debt maybe you hire one company for one case and hire another company for another case but you don't care how they actually do their job as long as they do it and collect the debt and this is an interface where you provide instructions on what needs to be done but you don't provide the implementation on how it needs to be done the how part is up to the concrete implementation of this interface so the first thing we need to do is create an interface and the way we create interfaces is similar to the way we create classes instead of using the class keyword we use the interface keyword so i'm going to add the new interface within the app namespace and i will call it depth collector and this is purely conventional some developers like to append interface or contract at the end of the name but i don't always do that so i would suggest to follow the convention that your team follows or maybe the convention that your framework follows or just pick some kind of convention and just stay consistent across your code base let's add the method that collects the depth because we want to make sure that concrete classes that implement this interface provide the implementation for that method so we let public function collect that accepts all the amount as the argument and returns the collected amount next we need to create the actual concrete class that implements this interface let's say that we're working with some sort of debt collection agency and i'm going to add that class within the app namespace as well so let's call that class collection agency and this concrete class can implement interface by using the keyword implements and then we can provide the interface name which is depth collector in this case as you can see as soon as i made this class implement this interface we're getting this underlining in ide letting us know that some methods haven't been implemented and that's one of the rules of interfaces all the methods that are declared within the interface must be implemented within the concrete classes that implement that interface so we need to add that method here now that error is gone before we actually implement this method let's go over some of the other rules of interfaces all methods declared with an interface must be public meaning that you cannot have private or protected methods they must all be public and similar to inheritance the same signature compatibility rules apply to implemented methods you can force concrete classes to have magic methods for example let's say that we wanted the collection agency class to have a constructor we could add the constructor declaration within the interface so we could do something like public function construct and now all the concrete classes must have the constructor so if we go here we're getting that underlining again and we could simply define the constructor here and the error is gone with inheritance he could only extend a single class but he could implement multiple interfaces which means that we could comma separate interfaces here and this will work we could add another interface and now we have this class implement two interfaces and you must have the implementation of all the methods that are declared within those interfaces if we had some kind of method here called foo then this method has to be implemented within the concrete class in the case where you're implementing more than one interface and the method names are the same it can result in errors if the signatures don't match or they're not compatible however on the other hand if the signatures of those methods are the same then you will not get any errors and everything will work as you remember extends keyword can be used in inheritance to extend from a single class however you could use extends keyword within an interface to extend multiple interfaces let me show you what i mean so if i go to that collector here we can have the debt collector interface extend one or more interfaces so we could say that this extends another interface and it also extends some other interface and this is perfectly fine what's going to happen is that any concrete class that implements this interface will have to provide method implementations for all the methods declared in this interface and all the methods declared in all the interfaces that this interface extends if we switch over to collection agency right now it's underlining because we're implementing the debt collector which also extends another interface so this is redundant and we don't need to implement this interface because it's already implemented within the debt collector interface so we could remove it from here and everything should work and last but not least thing to know about interfaces is that you cannot have properties in interfaces but it could have constants so for example in the debt collector we cannot have something like public int x but it could have constants you could do public const my constant equals to one and this works the same way as the regular class constant the difference is that constants defined in interface cannot be overridden as you remember from the inheritance lesson you're able to override the constants however when you define a constant within the interface you cannot override it within the concrete class so we cannot do something like public const my constant this is going to result in an error and it's not going to work all right so now that we've covered most of the theory let's actually implement the method and continue with the code so i'm going to revert all this and remove them and let's continue with the collect method so as i mentioned there could be different ways of collecting debt right maybe makes a call to the third party api to do the debt collection or maybe does some other business logic for now let's simulate this by using random number generator so we could say that this collection agency guarantees that they will collect at least 50 percent of the old amount so we can say that guaranteed amount is 50 of the old amount so we can simply multiply all the amount by 0.5 and then we could return a random number between the guaranteed amount and the old amount so we could do empty rend and we could pass in the guaranteed as the minimum and o the amount as the maximum now one thing to note here is that empty rand accepts integers as the arguments and we're passing in floats but this is okay when we're not using strict types but if we were to enable strict types then this would result in an error and then you would have to make sure that you're passing an integer instead of the float but for now we don't need the strict types for this example and this is fine now let's test this out we go to the index.php and let's create a collector instance and let's echo out the collected amount so we can do echo collector collect and let's say that we're old hundred dollars and see what we get in the terminal let's add a new line here and let's run the command and we get 83 let's run it again 98 and so on so as you can see it's a random number within the guaranteed amount and the full old amount so this works fine but what is the problem that we're trying to solve or what is the problem that the interfaces solve because we haven't encountered any issues so far right so what we're going to do now is that we're going to introduce the problem into the code so that we can see the importance and the usefulness of interfaces and how and what problems it actually solves to do that we need to have a method that accepts the debt collector as an argument it could be another class or maybe it could be a service class of some sort so let's create a class within the app namespace and we'll call that that collection service and within the service class we could have a method that collects that so we could have something like public function collect depth and this takes in the debt collector as an argument so we could say collection agency collector and the goal of this method is to figure out how much that is owned then call the collect method on the debt collector instance and finally maybe do some processing but for now we'll just print out on the screen how much of the debt was collected out of the total old amount so we'll have old amount variable and we'll set that to a random number between 100 and 1000 and then we'll set the collected amount to the value of collect method on the debt collector instance and we'll pass in the old amount as the argument here and then we'll simply print out collected this amount out of the total old amount all right so we go back to the index.php and instead of creating an instance of collection agency let's create the instance of that collection service we'll call this service and instead of hard coding the value 100 here we'll simply call collect that and we'll pass in an instance of collection agency as the argument now let's run the code again and as you can see everything is still working as expected it collected 801 out of 826 collected 643 out of 721 and so on so since everything is working what is the problem that we're trying to solve if we go back to the collection service here the problem is that we're being too specific about the implementation right here we're saying that this method accepts a collector argument and the type of that collector is collection agency so we're being very specific on what type of implementation of the debt collector we are accepting but what if down the road we wanted to change the debt collector maybe we wanted to hire rocky to collect our debt or maybe move to another agency we would need to update a lot of code and it would be a lot harder to maintain that code base to demonstrate this problem let's create another debt collector class and we'll call it rocky now because rocky is another type of debt collector we could have it implement the debt collector interface and then we need to implement that method now as i mentioned before different types of debt collectors can have different methods of collecting debt in the collection agency we use the random number generator but in the rocky let's say that he always no matter what collects 65 of the debt and returns that to the customer the rest he would keep it to himself so we could simply return the 65 of the old amount so now if we go to index.php we can just move on and use rocky but if we try to run the code now we get this error that the wrong type was used and that makes sense right because the collect that accepts collection agency because we're being very specific here and when we pass in another debt collector like rocky it's going to fail so this is the problem we assume the specific implementation and because of this you might hear or might have heard the phrase program or code to an interface instead of implementation because this method should not care what the implementation is it should just care that some sort of implementation of the common interface is given to fix this problem we need to use interfaces and because both our debt collectors doraki and the collection agency share a common interface we could simply use that interface to type hint this argument so we could do that collector and now this class does not care about the specific implementation the only thing it cares about is that some sort of implementation of this interface is given as the argument this is also called polymorphism which is the last principle of object-oriented programming that we haven't covered polymorphism simply means many forms an object can be considered polymorphic if it can pass multiple instances of checks which would indicate that it can take many forms we're accepting an implementation of that collector here can this argument pass multiple instances of checks an instance of keyword can be used to check if a variable or an object is an instance of some other class so we can do something like var dump collector instance of rocky and this will return true if this is instance of rocky now can this be true the answer is yes because rocky implements the debt collector interface and therefore collector could be instance of rocky he could also pass the second instance of check with the collection agency instance because collection agency also implements the debt collector interface and because it passes multiple checks of instance off then this argument can be considered polymorphic on the other hand when we had the concrete implementation of the collection agency here this would not pass more than one instance of check and therefore it is not polymorphic so let's change it back to the debt collector interface and let's run the code as you can see everything is working and we're passing in an instance of rocky and we know that it will always get 65 of the old amount and as you can see it's always getting the 65 we can change this to another implementation like collection agency and we run the code again and it will still work and then later maybe we added another collection agency company that implemented the that collector interface but their method of collecting money was different and they had different guarantees and stuff then we could also use that instead of this and we could simply just swap it out and our code would still work so we said that interface is like a contract and also we said that polymorphism can be implemented using interfaces because an object can take many forms can't the same be done using abstract classes with abstract methods the answer is yes because abstract methods kind of enforce a contract to the concrete classes and also polymorphism can be implemented using abstract classes and inheritance because an object can pass multiple instances of checks but the problem is that it makes you use inheritance which might not be a good idea in some cases as we discussed in the inheritance lesson so what's the difference between abstract classes and interfaces abstract classes can have regular methods that contain the body while interfaces can only have the method declarations without the body abstract classes can have properties while interfaces do not have any properties abstract classes can have private or protected methods while interfaces must have all methods declared as public and another difference is that it could only extend a single class while you could implement multiple interfaces so can these two somehow work together can we have interfaces within abstract classes and the answer is yes you could implement interfaces within your abstract classes you might have an interface that defines a contract or set of methods that need to be implemented and then you define an abstract class that implements that interface and you're still enforcing the contract to your concrete classes while also providing some base functionality to make this clear let's actually see an example of where abstract classes and interfaces could work together let's look at the example from the last lesson where we had the abstract base field class that had an abstract render method and then we had the text field and the checkbox field and radio fields extend from it so let's open that base field class here and let's see what we could do to implement an interface we have the render method that returns some sort of string or html right what if we made an interface called renderable that declares the render method let's do that and see how it improves our code so let's change this to implements renderable and we could create that interface and we could simply move this in here and we could remove the abstract keyword and now everything will still work as it worked before what this also allows us is that we can now use the renderable interface in any other class that needs to render something so does this mean that you should use interfaces for every single class absolutely not as with everything else interfaces have their use cases and their place you can think of it this way can your class have multiple different implementations if the answer is yes then interfaces would be the way to go also if you find yourself doing bunch of conditionals to check the type of a class using instanceof or maybe using some kind of switch statements that's another indicator on where interfaces and polymorphism could be used you could also reach for interfaces when you want to provide a contract or a template without implementation details now that we're done with our example let's look at some other more practical examples and see where interfaces could be used as you remember in one of the previous lessons we covered the psr standards if we go to the psr website we see that there are some standards that need to implement interfaces for example psr3 has a logger interface as the title and let's open that and see what it is it gives you all the information you need here with the specification and if we scroll further down we see the actual interface here we see that it provides the documentation and the declaration of all the methods that any concrete class implement in this interface would need to implement so where would this be useful for example during development maybe you want to log it to your local file system while in production maybe you want to log it in a database or maybe you want to send the logging to a third-party api that sends you an email or messaging slack or something like that so you would have multiple different drivers that would implement the same interface and you will see these interfaces being implemented in the modern frameworks today if we go back to the standards table we see that there is caching interface as the psr-6 and we have the container interface and we have the http message interface and so on let's open the caching interface and it's similar to the logger interface in a way that it provides all these methods that need to be implemented by the concrete classes you might want to cache it with redis or with memcached and so on so this basically allows you to swap out the actual implementation even during runtime for example laravel provides multiple different drivers for caching database queues and so on and they all conform to some sort of interface if you wanted to add your own driver you would simply just need to implement that interface and provide implementation for those methods so this is it for this video i hope you enjoyed it let me know in the comments if you have any questions or feedback thank you so much for watching and if you want to support me and this channel and you get value from my videos simply hit the like button subscribe and share to help me with the youtube's algorithm thanks again and i'll see you next time
Info
Channel: Program With Gio
Views: 29,965
Rating: undefined out of 5
Keywords: advanced php course, learn php the right way, object oriented php, php, php course, php in 2021, php tutorial, php oop tutorial for beginners full, php8, polymorphism, php interfaces, php polymorphism, abstract vs interface, interfaces vs abstract classes, what is polymorphism, what is interface
Id: -AJic0FjuAA
Channel Id: undefined
Length: 18min 2sec (1082 seconds)
Published: Tue Apr 20 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.