Achievement Type Requirements 0:00An abstract class provides a template, or base, for any subclasses. Let me show you through an example. Let's continue with that idea of achievement types. So we had one called First1000Points. If a user reaches 1000 points in your application, they get an achievement type. And we discussed that for each achievement, we need a name, maybe an icon, and then also a qualifier that will accept the user, and then determine, does the user qualify for this achievement type? Okay, so let's stick with two, and then we'll work our way up to an abstract class. So there's one, and then maybe this next one is your first best answer.Okay, so let's stick with two, and then we'll work our way up to an abstract class. So there's one, and then maybe this next one is your first best answer. Okay, so yeah, we could hard code these. I could say, First1000Points, and then this would be, you know, maybe the same thing, First1000Points.png. So if I were to grab those, move them over here, and then update, FirstBestAnswer, and then right here. Yeah, so you're starting to see some repetition here. And if we have 20 different achievement types, and if all of those achievements follow the same convention, it's a shame that we have to repeat ourselves over and over. Creating a Base Class 1:05And if we have 20 different achievement types, and if all of those achievements follow the same convention, it's a shame that we have to repeat ourselves over and over. Instead, I wish we could simply read the class name, and then figure out these values dynamically. Okay, so yeah, it sounds like we need a parent class to provide a template of sorts, or a base. So we'll create our achievement type class, and now we're going to figure out these dynamically. You can override them if you need to, but by default, you don't have to. So in this case, of course, we can't hard code it. Instead, we're going to read the class name itself. Now quick heads up, if you use Laravel, you can use a helper function called classBasename, Deriving Names Dynamically 1:38Instead, we're going to read the class name itself. Now quick heads up, if you use Laravel, you can use a helper function called classBasename, but I don't have access to that. So instead, I'm going to use simple reflection, and actually, you'd be surprised. This ends up being very fast. So we'll get the short name. So this will give us the name of the class by itself, without any namespace prefix. All right, so now if I have first thousand points, I ultimately want that to be first space thousand space points. So maybe I could do, let's do this together.space thousand space points. So maybe I could do, let's do this together. Let's look for, in this string, a capital letter. Not a lowercase, a capital letter. And I'm going to replace every occurrence of that capital letter with a space, and then whatever that letter was. Finally, I'm searching through the class. So let's return that and try it out together. Right down here at the bottom, I'm going to start by instantiating the achievement type. But that already feels a little odd.Right down here at the bottom, I'm going to start by instantiating the achievement type. But that already feels a little odd. We'll talk about this more in a minute. I don't love that I can instantiate that parent class directly. Okay, but anyways, if I were to grab the name, echo the result, and if I were to run this inline, whoops, we have a reflection issue. Oh yeah, sorry about that. We have to pass in the instance. So if I run it again, there we go. It works.So if I run it again, there we go. It works. But you know what? There's a little space there at the beginning. Oh yeah, of course. Let's just trim for now. And there we go. Okay, so now that works. For the icon, again, let's be quick. Let's grab that name. Generating Default Icon Names 3:09For the icon, again, let's be quick. Let's grab that name. And then how about this? Let's look for any space, replace it with a dash like that. And now if I were to grab the icon, and if I run it again, we get that. We just need to update a couple of things. We'll ultimately add .png to the end. And then finally, this should be lower. All right, if I run that, once again, we have our default icon name. Okay, so now think about it.All right, if I run that, once again, we have our default icon name. Okay, so now think about it. For these subclasses, they no longer have to override it. Instead, they will extend the parent class. And we'll do that here as well. Okay, so now if I instantiate first best answer, and we grab the icon, that's correct. And if we grab the name, that too is correct. Okay, but yeah, let's bring it back to what we had before, where we were instantiating achievement type. That feels wrong. Making the Class Abstract 4:06where we were instantiating achievement type. That feels wrong. The entire purpose of this class was to provide a base of sorts. But I don't actually want you to instantiate this ever. It wouldn't make sense. So here's what we can do. I'm going to change this to an abstract class. Now immediately, you'll see PhpStorm begins to squawk. So if I give this a run, it's going to fail. Cannot instantiate an abstract class.So if I give this a run, it's going to fail. Cannot instantiate an abstract class. Okay, that solves that problem. You can never instantiate this. You always must instantiate the subclass, like so. However, let's create another one. Let's say you reach top 50, if you reach the top 50 spots for all users. But you do it like this, and then you instantiate it. And yes, you can grab the icon. However, notice that we forgot to include the qualifier. Enforcing Qualifiers via Abstract Methods 4:57And yes, you can grab the icon. However, notice that we forgot to include the qualifier. So at some point in our code, if we try to check if the current user qualifies for this achievement badge, it's not going to work. So this is where abstract methods come into play. We're going to say, all right, if you want to extend from achievement type, you also need to declare a qualifier that will accept a user. Now in the past, this would sometimes be done by throwing an exception. Something like that. So if you tried to give it a run, it would fail because an exception is thrown.Something like that. So if you tried to give it a run, it would fail because an exception is thrown. But yeah, instead, what we would do is declare this to be abstract. And if that's confusing, remember, abstract just means there's no actual code here. We are providing the signature, but there's no implementation. And that's the main difference between concrete and abstract. So that's why we're not including a body here. And as it turns out, we can't. We're forbidden from doing that by the language. Okay, so now let's try this out.We're forbidden from doing that by the language. Okay, so now let's try this out. So if we give this a try, again, we're expecting some kind of user instance. We don't have that, but something representing a user. So yeah, if we give this a try, it's going to fail. PHP will blow up. And it's saying, hey, this class you're trying to instantiate includes an abstract method that hasn't been implemented. Or in other words, there's no concrete implementation to read from. So you have to declare it.Or in other words, there's no concrete implementation to read from. So you have to declare it. All right, so we'll do that now. And again, here, you would determine if the given user qualifies for that achievement. So if I run our code again, it no longer fails. Okay, so now you've learned when you add this abstract keyword, it does a few things. One, you remove the ability to instantiate that class directly. However, unlike an interface, the class can still include any behavior or functionality that you need to. And that's why we say it's a template of sorts.any behavior or functionality that you need to. And that's why we say it's a template of sorts. However, it can also declare abstract methods. These are methods that it does not and usually cannot implement directly. It needs specifics from the subclass. But nonetheless, it's still a requirement. So if you're going to extend achievement type, you have to provide a qualifier. And in fact, in the future, when you begin learning more about design patterns, you'll come across things like the template method pattern that uses this approach. The parent class can execute any logic it needs toyou'll come across things like the template method pattern that uses this approach. The parent class can execute any logic it needs to while deferring the specifics when needed to the child class. And the child will fill in that missing logic or that missing functionality. So now, this is what we end up with, and this is what we want. Anytime you create a new achievement, you will inherit this default base or this default functionality. If you need to override it, fine, but otherwise, we'll stick with a default. However, you do need to provide a qualifier. And because the parent has declared this to be abstract,However, you do need to provide a qualifier. And because the parent has declared this to be abstract, there's no opportunity for you to forget. If you don't include it, PHP is going to blow up as soon as you run the code.