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

Iterating Basics in PHP0:00

Today's question comes via Twitter from Jigal Sanders, and he asks, can you please help me to get my head around iterators? Okay, fair enough. So we know the basic term, iterate, right? To iterate over something means to cycle through it, to filter through it. So we know already in php that we can do this with foreach, right? So foreach, one, two, three, as number, and then var_dump the number. We already know that we can do this, right? If we run it, php index.php, this is all very basic stuff. But what about when you need to iterate over something that's not a simple array? Well, how exactly does that look?

Iterating Over Objects0:35

But what about when you need to iterate over something that's not a simple array? Well, how exactly does that look? All right, let's imagine we have a class called User, and imagine you just have some public properties like their name, and I'm just going to hard code this for the example. We'll do John, and then John's age will be 25. Okay, well, yes, we could iterate over an instance of User like this. Now here's how this works. When you iterate over an object, yeah, you're just going to cycle through the public properties. So for example, if these became protected, if we run it again, no, that doesn't work.

When you iterate over an object, yeah, you're just going to cycle through the public properties. So for example, if these became protected, if we run it again, no, that doesn't work. So as it turns out, iterating over an object in this way very, very rarely is useful. What's more useful though is maybe iterating over a specific array that is contained within the object. Here are some examples to get you thinking. What about in php when you need to iterate over a MySQL query? Well, we know we can do that, right? Fetch some database results, and seemingly what's returned isn't just a simple array, yet you're still able to do a foreach or a while statement over it. Another option would be maybe scanning a directory.

yet you're still able to do a foreach or a while statement over it. Another option would be maybe scanning a directory. Exact same thing in php. Another one would be how about reading lines in a file. Exact same thing. So you open it, and then you would say something like foreach file end of file. You know, all those kind of awkward functions. Yeah, still an iterator. So there's lots of examples of needing to iterate over something that's not just a simple array. Now here's one that I use, and if you use Laravel, you use as well.

Why Collections Are Iterable2:11

So there's lots of examples of needing to iterate over something that's not just a simple array. Now here's one that I use, and if you use Laravel, you use as well. Imagine you have a Collection class. And as I sometimes put it, a Collection class is sort of like an array on steroids. It makes it a lot easier to interact with, has lots of helper functions or methods. It's great. But now how do you iterate over a Collection? Because we know we can do that in Laravel, right? You perform that database query, and that returns a Collection class so that you can say foreach $users as $user. Have you ever actually thought about how that's possible?

You perform that database query, and that returns a Collection class so that you can say for each User says user. Have you ever actually thought about how that's possible? Because this, the result of that, yeah, it's an instance of a Collection class. It's not an array, but you can still iterate over it. Well, the answer is that Collection class implements, well, not the iterator class. It implements something called IteratorAggregate. And this is sort of like a streamlined way to use iterators. I'm going to show you both, though. All right, let's try it out. The class Collection, it will be composed.

All right, let's try it out. The class Collection, it will be composed. I'll use a macro for this. Anyways, it'll be composed with an array of items. So that means I could say $collection equals a new Collection, and then the items will just be A, B, and C. Okay, so now we want to iterate over not the public properties on the Collection class, but the items within it. All right, let's try this. We're going to say foreach $collection as $item, var_dump the $item. But as we know, this is not going to work like we expect. In fact, we get nothing at all.

Using IteratorAggregate3:48

But as we know, this is not going to work like we expect. In fact, we get nothing at all. All right, let's fix this. We're going to have the Collection class implement an interface called IteratorAggregate. Now, if we run it, it's going to fail, and it's going to let you know, well, you're implementing an interface, so you have to declare the getIterator method. Now, the way this works is you have an Iterator interface, and if you implement it, you have to define five different methods that basically specifies what you're iterating over and how you do it. Now, with IteratorAggregate, it streamlines that process greatly by only making you define one method that will return an external iterator, such as one that the PHP-centered library provides, and then you're all set to go. So now we could do this. If PHP already provides a bunch of custom iterator classes, such as ArrayIterator, and now we're going to pass through whatever it is that we want to iterate over. And that's it.

If PHP already provides a bunch of custom iterator classes, such as ArrayIterator, and now we're going to pass through whatever it is that we want to iterate over. And that's it. So by implementing a single interface and adding one method, we've added support for this. So that means if we run it again, we should get A, B, and C, and we do. It's as simple as that. So if you're curious and you're using Laravel and you check out your Illuminate\Support\Collection class, you're going to see something just like this, implements IteratorAggregate. Now, one quick note, though, you have to implement this. So it's not a situation where as long as the method is there, everything will work behind the scenes. No, not going to work. It's mandatory that you add this section here because it'll be checked for behind the scenes.

No, not going to work. It's mandatory that you add this section here because it'll be checked for behind the scenes. Now, when it comes to things just like this, very, very simple stuff where maybe you have one array within the class, and when the user calls forEach, that is the thing that you want to iterate over. In those cases, this is the contract you want to implement. So implement IteratorAggregate, create a getIterator method, and then return typically an ArrayIterator and pass through the array that you're cycling through. But as it turns out, in lots of scenarios, you need quite a bit more control. You're not just dealing with a simple array. And this is where I was talking about reading a file or doing something else that's very custom and in need of precise control over how it's iterated. So let's try this. Let me show you the basic skin of it.

Implementing the Iterator Interface6:13

So let's try this. Let me show you the basic skin of it. Let's begin with a simple class Counter so I can show you all the methods. We're going to have this implement Iterator. It's going to be very, very simple, kind of a trivial class. So right off the bat, if we try to run this, it's going to fail. If you want to make your class an Iterator, you need five different methods, current, next, key, and it's cut off, but the others are rewind, and then finally valid. So basically, these methods determine what it is you're iterating over and how you switch between the items in that collection or array or set of data. So for example, current. How do you define what the current item is?

So for example, current. How do you define what the current item is? Well, with a typical array, you can use something like this, current, and then maybe the items you have. That's how you do it. If you want to get the key, then often you'll do something like key and then maybe reference the array, right, and generally you would return these. Okay, let's keep going. The other one would be rewind. So this is how you rewind to the beginning of the data or the collection or the array. With php and arrays, once again, you have a reset function. So bring the internal pointer back to the very first item in the array, essentially.

With php and arrays, once again, you have a reset function. So bring the internal pointer back to the very first item in the array, essentially. Okay, so you have current. Give us the current value. The key, give us the key for the current value, so like foo equals bar. So current would return bar and key would return foo. rewind would be, let's say you've iterated over it a few times. rewind will bring it back to the very first item. And remember, these methods, you're not calling them directly. Behind the scenes, php is going to reference these to determine how to iterate over the items.

And remember, these methods, you're not calling them directly. Behind the scenes, php is going to reference these to determine how to iterate over the items. Anyways, we also have a next method. This brings the internal pointer to the next item in whatever your data happens to be. There's a next function for this. So you could do this. And then finally, there is a valid function. And this is how we determine are there more items left in this data set. So can we keep going? Because remember, you have to tell it, you have to tell it when to stop cycling through.

So can we keep going? Because remember, you have to tell it, you have to tell it when to stop cycling through. It doesn't know. It may not be an array. So we have to be explicit about that. And you could always just do something like this. Return this items and then maybe grab the current one. And that will automatically be cast to a Boolean, but you could be explicit if you want. So get the current value. And if that is truthy, then we're all set to go.

So get the current value. And if that is truthy, then we're all set to go. But if it's falsy, then no, it's not valid anymore. And like I said, this will automatically be cast if you return it. So either one is fine here. So yeah, this is the basic skin you would use. So for example, let's bring it back to collection just for a minute before we use counter. And we'll do that thing again where we give it some items. And we'll save that up here. And now down here at the bottom, create a collection one more time, A, B, and C.

And we'll save that up here. And now down here at the bottom, create a Collection one more time, A, B, and C. And now I can say foreach $collection as $item. And basically, we're going to get the exact same thing here. So if we run this, yeah, A, B, and C. So this would be the long form way of doing this. So we're going to implement Iterator. And we'll have to define the five different methods that describe what it is you're iterating over and how exactly that should be done. How do we determine what the current one is?

and how exactly that should be done. How do we determine what the current one is? How do we switch to the next item in the set? How do we get the key for it? How do we reset or change the internal pointer back to the very first item in the data set? And then how do we determine if there's more items to iterate over? That's the long form. But as we learned, if you're just iterating over an array, well, then you don't need to bother creating your own iterator. You can do iterator_aggregate and then defer to one of PHP's specific iterator classes.

well, then you don't need to bother creating your own iterator. You can do iterator\_aggregate and then defer to one of php's specific iterator classes. And there's tons of them. There's database-specific iterators. There are directory iterators. And there are array iterators. New ArrayIterator. Give it our items. And now we've replaced those five methods with one. Okay, but let's bring it back.

Building a Custom Counter10:36

And now we've replaced those five methods with one. Okay, but let's bring it back. You already know about iterator aggregate. So I'm going to undo a few ways. A few clicks, I mean. And now we have those five methods. Let's bring this back to counter now. And we're just going to have a little bit of fun. We will say counter start. And we're going to give it a number here.

We will say counter start. And we're going to give it a number here. So we'll say count. And then we will assign that here. So here's the goal. Like I said, it's kind of silly, but this will be our little goal. We're going to say counter. And you know what? Why don't we make this a static method? So we'll say return new static and pass that through.

Why don't we make this a static method? So we'll say return new static and pass that through. And then we'll accept this in the constructor just to make it a little cleaner. Okay. So does this all make sense? And I'm sorry, that can leave. So we can say counter start at 5. And that's just going to new up the class and nothing else. So let's try it. Down here.

And it's going to go indefinitely unless we're explicit about when we are done counting. All right. So we'll say for each counter as number. var_dump the number. Okay. So before we run this, let's go through the process. counter start. We'll hit this method that will create a new instance of our Counter class and pass through the current count, which we will assign. Next, these various methods will be called internally by PHP in order to iterate over everything.

which we will assign. Next, these various methods will be called internally by php in order to iterate over everything. But, yeah, now at this point, we don't have an items array. So we have to do it custom. We need greater control over how we do this, which is specifically why we're using implements Iterator instead of implements IteratorAggregate. Okay. So what would the current item be? Well, it's whatever count happens to be. And remember, we return that.

Well, it's whatever count happens to be. And remember, we return that. Okay. How do we go to the next one? Well, we just kind of check it up. We click it up. This count plus plus and return that. Next, what is the current key? Yeah, nothing special here. We can return current as well.

Yeah, nothing special here. We can return current as well. How do we reset it back to the beginning? Well, why don't we say this->current equals. We could do 1 if we begin at 1, but we don't necessarily do that. So maybe we should also say, so this->start equals count, and then we can remember that as well. Now we know what the user wants to begin at. So if we come back and rewind it, we could say this->current equals this->start. Finally, valid. That's going to be an important one.

Finally, valid. That's going to be an important one. Let's just try this. This current is less than or equal to 50 or 20. Okay, so does this all look good? By the way, we should update this. But yeah, it seems kind of complicated, but it's really not. So if I run it, sure enough, we count or we iterate up to 20. And like I said, internally, it's referencing these methods to figure out what are we iterating over, and how do we do it?

And like I said, internally, it's referencing these methods to figure out what are we iterating over, and how do we do it? How do we go to the next one? What does it mean to go to the next one in the data set? Well, in this particular case, it means to increment a number. To rewind it, it means to reset the current count to whatever we initially started with. And then finally, valid. Well, in this case, it's a bit arbitrary, but maybe we could set the end. So we could say count, and why don't we rename this? So we'll start and end, and then we'll pass that through.

So we could say count, and why don't we rename this? So we'll start and end, and then we'll pass that through. And then we'll accept it and store that. And that means we're going to have to update this, too. You know, it's important to name your variables properly. Sometimes people get lazy. I know I do, too, sometimes. But it's really important that you labor over this. Don't just accept a variable name that is not incredibly clear what it refers to. Anyways, we'll set the end.

Don't just accept a variable name that is not incredibly clear what it refers to. Anyways, we'll set the end. And now we can store all of this. So that means current will still return current. To move to the next item means to increment current. The key is the same. To reset it, well, we update current equal to what the user started with, in this case 1. And then valid, well, it'll be valid just as long as the current is less than or equal to the end. And we'll set this to, how about, 100. Okay, if we run it now, we go all the way up to 100, and then we stop,

What you may do, like I said, is implement IteratorAggregate, which is a drastically more simple approach. But yeah, if you need fine-grained control over your data and how you iterate over it, then you will implement Iterator. And that's it. So if you'd like to learn more, the PHP Standard Library has, I think, dozens at this point of iterator classes, like I said, for interacting with your database or scanning files or reading directories or tons of stuff. So go have a look. You'll find a collection of them, of course, on the php.net website.

So go have a look. You'll find a collection of them, of course, on the php.net website. So here's the ArrayIterator you're familiar with. But then, yeah, going through your file system or if you're globbing or even if you're working with regular expressions. So lots of stuff here. Don't feel like you have to memorize all of these. You can start with ArrayIterator and maybe stick with that for a while until maybe you need to iterate over a directory and you're not using something like the Finder library or anything like that.

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