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

Recapping Interface Contracts0:00

Welcome back. So, let's return to interfaces one more time. A couple episodes ago, we discussed the general definition, right? And you learned that interfaces are sort of like contracts or agreements that any number of parties can sign. However, if you do sign that agreement, you have to abide by the terms and conditions, right? And usually that means implementing some kind of a method or two. All right. Next, we learned that interfaces can sort of be like the generic representation for a piece of functionality, right? And we use the example of a NewsletterProvider. So, that determines how we can subscribe a User to a list or fire off a newsletter. Then we can create any number of implementations. And each implementation is sort of like a party signing the agreement, right? So, we have one for Postmark. We have one for MailChimp. But both of them conform to the same API that was declared in the interface.

Interfaces as Feature Checks0:54

is sort of like a party signing the agreement, right? So, we have one for Postmark. We have one for MailChimp. But both of them conform to the same API that was declared in the interface. All right. But now there's another way that we can use interfaces. We can leverage them as feature checks or feature filters, if that works for you. Let me show you an example. So, imagine you have a class called Comment. And Comment should offer the ability to be liked. So, I can say comment->like(), and that probably updates a pivot table in your database. All right. So, we're going to have a method called like(). Next, we need some kind of Boolean check. Is this comment liked? So, now we have a method called isLiked(). And this is great. So, again, I'm just going to hard code this so we don't get trapped in the weeds. We really just want to focus on the general functionality or the approach. So, we'll say true. And then

So, again, I'm just going to hard code this so we don't get trapped in the weeds. We really just want to focus on the general functionality or the approach. So, we'll say true. And then here I will say like the comment to represent the underlying logic. Okay. So, this is great. But next, we offer a new class that can also be liked. How about a Post? How about a Post? All right. So, I'm going to copy this. And we will update the class name. And a Post can also be liked. Like the post. Very cool. So, now, imagine you have some kind of dedicated class that is responsible for everything required to like a model. And remember, sometimes that includes more than just updating a database table. Maybe you record activity. Maybe you fire off a notification. Maybe you email the person, hey, such and such post was liked. I thought you'd like to know. Right? So, when you have actions like this that consist

Encapsulating Likes in Action2:33

fire off a notification. Maybe you email the person, hey, such and such post was liked. I thought you'd like to know. Right? So, when you have actions like this that consist of any number of steps, we could encapsulate that within a dedicated class. And, yeah, this is an example where if you want, you could name the class something other than a noun. So, be very careful with this in the early days. But once you feel comfortable, feel free to use verbs for your class names. All right. So, maybe this class is called PerformLike. It's a verb. And that's fine. However, I'm going to let you know right now, not everyone agrees on that's fine. Right? So, sometimes they will get around it by adding maybe a suffix. So, they will call this an action. And now they return it to a noun by saying PerformLikeAction. This is the PerformLikeAction. But whether we call it that or we treat

maybe a suffix. So, they will call this an action. And now they return it to a noun by saying performLikeAction. This is the performLikeAction. But whether we call it that or we treat it like a verb, hopefully we can see it's the exact same thing. It just doesn't matter. All right. Just be thoughtful. And you should be okay. So, now, on this action, we'll have a method called handle. And this is going to accept some kind of model or class or an object that can be liked. And, yeah, like I said, it's going to update the database. It's going to fire off an email. It's going to display any number of things that might take place when this happens. Okay. But here's the problem. The first step is I need to check whether or not this model has already been liked. No problem. Because we can see on these two classes, they offer a method isLiked. All right. So, I could say, well, if not model.isLiked, then or why don't we say this? Let's do the inverse.

liked. No problem. Because we can see on these two classes, they offer a method isLiked. All right. So, I could say, well, if not model isLiked, then or why don't we say this? Let's do the inverse. If it already isLiked, there's nothing to do here. And maybe we should return early. Cool. I like this. So, why don't we give it a shot and see what happens? I'm going to instantiate performLike. And I will call handle. And I'll give it the Post object. Okay. So, let's see what would happen. Let's just go through it before we run the code. We instantiate this. We call handle method. We give it a Post object. We check if the Post isLiked. Well, the answer is yes. So, it returns early. Why don't we make this false? And then we could say, well, if it's not isLiked, then we could say model liked. And then we could proceed to all of the other things that need to take place as part of that operation. Cool. So, if we did everything properly, we should see

then we could say model liked. And then we could proceed to all of the other things that need to take place as part of that operation. Cool. So, if we did everything properly, we should see like the post. We give it a run. php. Whoops. php on the current file. And that's working great. Next, we can swap it out with our comment. And because comment also has a like and an isLiked method, we should be able to swap it out pretty easily. All right. Give it another run. And now we get, oh, let's go back up. Let's make sure we say false in this case. Yeah. Now we get the exact same thing. And this is great. So, what's the problem here? Well, nothing, really. This is kind of the true spirit of object-oriented programming. Because the Post class exposes this behavior and because Comment also does, then we can work with it. And this kind of goes back to that idea of if it quacks like a duck and it looks like a duck, then it must be a duck, right?

Duck Typing Breaks Down5:53

this behavior and because Comment also does, then we can work with it. And this kind of goes back to that idea of if it quacks like a duck and it looks like a duck, then it must be a duck, right? If you give this handle method an object that has the necessary behavior, then there's no problem. It doesn't matter what it is. If it can act like a duck, if it can quack like a duck, then we're going to treat it like a duck. That's an old phrase we often use. Cool. But now it turns out we introduced something new in our system, maybe a FormThread. And FormThreads can also be liked. So, let's create that now. We have a class called Thread. But let's say because there was no explicit contract here, I forgot that I needed some kind of isLike method. So, instead, I simply pass a Thread object that contains half of the required API methods. All right. Let's see what happens. I instantiate Thread. We give it a run. And we get a fatal error. Call to undefined method

pass a Thread object that contains half of the required API methods. All right. Let's see what happens. I instantiate Thread. We give it a run. And we get a fatal error. Call to undefined method Thread::isLiked. All right. So, this is a problem, right? We're trying to give it an object, but isLiked is expecting a certain API that simply isn't available on Thread. And that's why we get a fatal error. All right. So, what can we do here? Like, is there a way to add a type to enforce this? Well, let me show you something. Let's return this to new Comment. And you'll notice that if I say model and I see what methods are available to me, my editor doesn't provide any kind of auto completion because we didn't add a type here. So, model could literally be anything. It could even be a string here. So, that's not ideal, especially for larger code bases. It can be really helpful to see, well, what is available to me? What is the public API for this object?

Typing Options and Limits7:35

It could even be a string here. So, that's not ideal, especially for larger code bases. It can be really helpful to see, well, what is available to me? What is the public API for this object? Now, what if I give it a type of Comment? Well, that would fix it, right? So, now, if I run it, suddenly I see which methods are available to me. But, of course, because we are hard coding Comment, now we've drastically limited the surface area, right? So, if I now try to pass through a Post, even though a Post can act like a duck and quack like a duck, it is not going to work in this case because we were explicit that only a Comment is allowed. All right. So, I don't want to do that. I want to stretch this out. I want to make it a little more generic. So, our next possibility might be to use the or operator. I could say, all right, we accept a Comment or a Post, and we represent or using a pipe here. All right. So, now, you're right. That would fix the

Defining a CanBeLiked Interface8:23

possibility might be to use the or operator. I could say, all right, we accept a Comment or a Post, and we represent or using a pipe here. All right. So, now, you're right. That would fix the problem. Let's give it a run, and sure enough, this works like it did before. But now we're still in that same boat. I try to pass through a Thread, and now that's not going to work because it's expecting a Comment or a Post. All right. So, what do we do here? Well, what if we introduced an interface? And this interface doesn't just represent, like, the generic type of what the thing is, like we learned about two episodes ago. Instead, this interface represents a feature, something the interface can do or something the class can do. So, notice the distinction there. Two episodes ago, we discussed what an interface is, what it represents. But now we're going to use it in a different way to represent what the interface can do. All right. So, let's just think

Two episodes ago, we discussed what an interface is, what it represents. But now we're going to use it in a different way to represent what the interface can do. All right. So, let's just think of a type, any type we want. What do we need here? Well, this model, or what we pass here, needs to be a model that can be liked. That's sort of what it is, right? Just give me something that can be liked, and then I can work with it. All right. How about that? Let's use that for our type. Can be liked. All right. You have an interface now. Let's go to the very top, declare it, interface CanBeLiked. So, yeah, notice when it comes to what you name your classes and your interfaces, there's no real hard rules. You can do whatever you want. It can be a single word. It can be multiple words. You can add an interface suffix, if you like. I don't really like that, but plenty of people do. And that's the entire point. You are in charge. Okay. So, let's keep it

It can be multiple words. You can add an interface suffix, if you like that, but plenty of people do. And that's the entire point. You are in charge. Okay. So, let's keep it with canBeLiked. And now, our API is going to be, well, you have to offer a method called like, and you also have to offer a method called isLiked. Okay. So, let's see. I see Comment offers those methods. Great. Post does as well. So, could I instantiate Post and just have this work? Hmm. Let's see what happens. clear. Run it again. And no. We get a fatal error. So, we needed to pass something that was of type canBeLiked, but we gave it a Post. All right. So, this can be confusing because we're thinking, wait a minute. Post does conform to that API. It offers the methods that are required here. However, we didn't sign the contract. So, this is like a contract that wasn't signed. Yes, you might be abiding by it,

to that API. It offers the methods that are required here. However, we didn't sign the contract. So, this is like a contract that wasn't signed. Yes, you might be abiding by it, but you never signed the contract, so it's not being enforced. Okay. So, like we learned two episodes ago, we signed the contract by using the implements keyword. This can be liked. And then, let's do, excuse me, let's do the exact same thing for Post can be liked. All right. So, now, we've created an interface that represents what it can do, a feature, a filter. Now, any class that requires a model that can be liked can type not the name of the class itself, but the specific ability that we need access to. And again, we represent that ability as an interface. All right. So, now, Post has signed that contract. So, if we give it a run, it works. Comment has signed that contract. So, we give it a run. It works. And now,

as an interface. All right. So, now, Post has signed that contract. So, if we give it a run, it works. Comment has signed that contract. So, we give it a run. It works. And now, Thread is also going to sign that contract. Implements can be liked. And now, because we have an interface here, and we have a good editor, well, it's going to let us know, wait a minute, you're missing a method. Make sure you add isLiked. All right. So, that helps us. We update our API. And now, if I instantiate Thread, and we give it a run, this time, we get like a Thread. All right. So, now, you can see that we can use interfaces in two unique ways. And there is no right way, and there is no wrong way. It's just whatever makes sense for your project. They're both entirely fine.

for your project. They're both entirely fine.

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