Lessons: 18Length: 2.3 hours

Next lesson playing in 5 seconds

Cancel
  • Overview
  • Transcript

5.4 Traits

PHP 5.4 introduced traits. A trait is a class container in which you can group a set of behaviours that can be later ‘plugged’ in any class. How’s that for reusable code? In this video, we’ll create a small Curl trait and and setter/getter trait. Then we’ll include both of them in a single class.

5.4 Traits

Hello, and welcome to PHP OOP fundamentals. In the previous videos, we've covered quite some ways to decouple and encapsulate your code from the rest of your application, and we've also learned that creating very small and concise classes that do just one thing can be very helpful in that process. You could for instance, create a curl class that does nothing but launch a curl request. Now, that would be usable in several places. Well maybe a base class with magic setters and getters, and I could see us using that in several places as well. But then if you have all these little classes, it would be nice to also be able to extend more than one class at a time. It would be great if we could just do class user extends curl and magic. Well unfortunately, you can not do this in PHP. But as of PHP 5.4, there is a way that you can simply include multiple reusable classes into other classes. Meet traits. A trait is just that, a little class that is meant to be incorporated into other classes. I'll show you what I mean. We'll open up our Acme app folder, and inside of that, we'll just create a new folder, and we'll call that traits. Now inside, let's create a new file, and we call that Curlable.php. And all that will do is run a kernel request and return the results. First of all, I'll give it a namespace, and that will be Acme\App\Traits, and then here we'll just create a class. But instead of using the keyword class, we'll use the keyword trait. Now the rest of the syntax is exactly the same as creating a normal class. A trait of property and methods. In our case, it will just contain a public function called curl, and it will take just a single parameter called URL. Now like I said, inside of a trait, you can group a set of behaviors that can later on be plugged into any class. Now you cannot instantiate a trait. It's meant to be inherited into other classes. So inside of our curl method, we'll just do a regular curl call. We'll start with curl_init. Now that will give us a handler that will store into a curl handler, let's call it ch. Next, we'll just set some options with curl_opt. We'll take the curl handler, and the option we'll set is the CURLOPT_URL, and that will just be equal to the URL that we pass through this method. Now I'll just copy that line because I'd like to set another option called CURLOPT_RETURNTRANSFER, and we'll just set that to one. And that's all there is to it. All we have to do now is run curl_exec, pass in the channel like so, and store the output in a result variable, then we'll just curl_close the channel like so, and all that's left for us to do is, well, simply return the results. It's a very simple trait, but it does the trick. So now, I have a very small, concise piece of code that does nothing else but call a curl request. Now let's see if we can incorporate this trait into another class. Tell you what, why not use this trait inside of our user class that we have here? Let's open that one up. Now this is our abstract class, but if I incorporate the trait here, then it will also be incorporated in all of the child classes for this user class here. Okay, now at the very top of the class, we'll include our Curlable trait. And we'll just do that with the keyword use and then followed by the name of the trait which is Curlable. Now remember our Curlable trait is inside of a different namespace. So, we need to make provisions for that. Let's just use Acme\App\Traits\Curlable. Now see if we can just instantiate one of the user child classes inside of our index.php and run it in the browser. Now if all's well, we shouldn't get any errors. I'll tell you what, we still have our administrator class here and that extends users, so let's instantiate that. Inside of our index.php, we'll run a new acme app administrator, and we'll just store that inside of a variable called administrator, like so. Now, let's run this baby in the browser. And there's our first error. It seems like I forgot to prepend Acme namespace with a backslash. So let's go back to the user class and make sure we use \Acme\App\Traits\Curlable. Okay, our error's gone. Let's see if we can implement our little curl functionality here. I'll just create a new property at the top, and we'll just call that facebookid. Let's make sure to add that to the fillable array, so facebookid, and let's also add it to the accessible array, facebookid, like so. And now remember, we have our set and get methods, the magic methods. Let's just replace this if set statement with something else. Let's instead use property exists. We'll pass this as a class and we pass name as the name of the property, like so. Because instead, we'll return false if the property is null and we'll just do the same here with the get methods. So property exists, this comma name. Okay now that we're all set to set our facebookid, let's do so in index.php. We'll pass an array to the constructor of our It will have a key of facebookid, and let's see what facebookid shall we use? Let's for now just do tutsplus. Now let's see if we have defined the constructor in our child class, and yes we have, but it's not taking any parameters. So we'll just make sure that accepts an array. Let's call that params and that will be equal to an empty array if nothing's passed. And then the first thing we need to do here, is call the parent constructor and pass that params array. Now before we go using our Curlable trait, let's just check first to see if we haven't made any errors. Lets just do a var dump of our administrative variable here, and check that in a browser. And yes there you have it, here's our facebookid, and it's set to tutsplus. So that's okay. So we have a facebookid. Now let's just use our curled trait to actually retrieve some Facebook data. And what better place to do that than inside of our abstract parent class. Okay, scroll up to the top here and right below the constructor we'll create a public method and let's call that getFacebookData. Now, inside of the method, we'll create a variable called url and that will contain the URL to the Facebook graphs. So that will be http followed by graph, and I think it is Facebook.com, then followed by a slash and the username. Well, we already have that, it's stored in this facebookid. And all that we need to do now is return this and this is where the our trait kicks in. You see we have Curlable trait. It contains a method called curl. And that will just finally be inherited by our user class. We will now have access to a method called curl and that will take a URL as a parameter. And just for good measure, let's run that through JSON decode I think. Like so and maybe pass through as a second parameter so we get a multidimensional array as the output. And now instead of dumping administrator, let's just dump administrator getFacebookData. Well if our Curlable trait is in fact successfully included inside of our user class, then the curl method here should have been inherited by the user class, which in its turn should be inherited by our administrator class, okay? Let's check to see if this all works. We'll fire up our browser and there you have it. All the publicly available data from Facebook for the account Tuts+. Now I told you classes can inherit from multiple traits. So let's see if that is actually true. Remember that inside of the user class, we have this set method and the get method. Well maybe we could move these methods to a trait, and make them available to every class that actually uses that trait. I'll just cut these to the clipboard like so. Okay, now the first thing to do is create a new trait. Let's just call that Accessible, like so. We'll give it a namespace of Acme\App\Traits. And then we'll just create a trait with the name of Accessible. I'll just paste in the contents of my clipboard. Now let's just go over these magic methods again. If we're trying to set an inaccessible property, we are first checking to see if it's name is in a fillable array. Okay, well let's see if we can define that fillable array. At the very top here, we'll just make a protected fillable array, and that will be equal to an empty array like so. Now, here we are returning false if our variable is not inside of this fillable array. Well, that's quite a good validation rule, but only if the fillable array actually contains any items. So let's do another check and see if a fillable array is actually filled with some items, then if our property is not inside of the fillable array, we'll return false. And if this test passes, then we'll do another test and say if the property exists and now we're using the keyword this. So what does this refer to here? Would it refer to the trait or would it refer to the class that actually uses this trait? Well, because the entire accessible trait is inherited by the user class, this can refer both to the accessible trait and to the user class. So yes, we should be able to use this here. Now here inside of our get method, we have a similar if statement where we're checking to see if our name is in an accessible array, and let's add the same checks we did above here. So let's see if we actually have any items in our accessible array, and only if we do, we check if the name of the property we wish to retrieve is inside of that accessible array. Okay, now we haven't used the Accessible trait yet. So if inside of our index.php, I were to try to access our administrator facebookid. That is, without setting it inside of the constructor, then that should throw an error. And it does, like we expect it to. I can not access a protected property called facebookid, okay? Good. Now we'll open up our user class, go to the very top, and copy this line here. And apart from the Curlable trait, it will also import the Accessible trait, like so. Now, there is a little catch. Inside of my Accessible trait, I declared a protected variable called fillable. And while we're at it, I should copy this because we also need an accessible property like so. Now because I define it inside of my trait, I cannot define it again inside of my user class. So that is inside of the class that actually inherits this trait. So let's just remove these from our class entirely, and just sit them inside of our constructor. So well do a this fillable array, and we know that it exists because it's in our Accessible trait, and we'll just add a new index. We'll set that to an empty string for now. Copy it three times. And the items that we need to add is email, password, and of course, facebookid. Now we'll copy this three times once more, and we'll also add these to the accessible array. One and two and three. You see just because we can't define these properties doesn't mean that we can't work with these properties. Okay, so once more, inside of our index.php, we are trying to access the facebookid, which is inside of our accessible array, so that shouldn't give us any problems whatsoever. Well, that is of course, as soon as I set the administrator facebookid to a certain value, so we can actually retrieve some Facebook data. Let's just set it to joostvonveen for now. Okay, we should firstly see our facebookid and then see our Facebook data. Let's fire up our browser, and here's our facebookid and yes, here's our Facebook data. So that all works, and just one final check to see if we're actually setting our facebookid through our magic Accessible trait, let's just remove facebookid from our fillable array. And now we should be in a heap of trouble here. And yes, we're not able to set our facebookid, so we are retrieving an error from our Facebook open graph API as well. Okay, so in conclusion, about traits. They provide a ready-to-use behavior, and that is in the form of a set of methods that you could easily plug into any class that you wish. Number two, a trait is for inheritance only. A trait cannot be instantiated by itself. And number three, a trait can force it's containing class to implement certain methods and that will be the last example for this video. All you need to do is create an abstract public method. In our case, we could for instance, define a method called getProperty or something like so, and just defining this abstract method here inside of our trait forces our contending classes to define this method as well. It's a bit like with an interface. You see when I reload my administrator class in the browser, we are getting a fatal error because our administrator class does not define our abstract method. And you'll see that if I go back to my editor, open up the user class, and just simply define that public method here, then that fatal error will have simply gone away. Okay, well that's all for traits. Just one final note of caution. While traits are very powerful, make sure not to overuse them. Because while it is possible to include maybe 20 traits in a single class, that can lead to a very complicated coding route. And if you add to that that you can even incorporate traits within traits, well you get the picture. If you go down that route, pretty soon, you'll be wading up to your knees in spaghetti coding again. Okay, well that's all for now. Happy coding, and I'll see you in the next video.

Back to the top