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

Adding a Playground Test0:29

So as you can imagine, when this is done, it's going to look much more attractive, we'll have spacing, we'll have search. I think it's going to be pretty useful. But now, having said that, as I was working on this, I ran into a few snags that I think we can clean up. And I'll run you through a few of these. So right now, the suite is passing. So at the very bottom, I'll add a new test here, and we'll just call it Playground, as we tinker around. Okay, so yeah, I can say this transcription, and I can grab our lines.

we tinker around. Okay, so yeah, I can say this transcription, and I can grab our lines. And let's run that through var_dump. And sure enough, we get what you've seen a number of times at this point, a lines collection consisting of any number of line objects. Now it is true, because we implemented IteratorAggregate, we can, well, iterate over each item within that collection. But let's do this. If I have a lines object here, I ran into a situation where I wanted to access each item like this.

Supporting Array-Style Access1:19

If I have a lines object here, I ran into a situation where I wanted to access each item like this. So here I'm interacting with the lines collection as if it was an array. So if I give this a run, it's going to fail with an error. You can't use an object as an array. Okay, so how does this work? Because if you're familiar with Laravel, whenever you're working with a Laravel collection, you can interact with it in this way. So what exactly is going on here? Well, what's happening is behind the scenes, the collection is implementing a particular

So what exactly is going on here? Well, what's happening is behind the scenes, the Collection is implementing a particular interface called ArrayAccess. Let's pull that in now and add the method stubs. So this allows you to interact with an object as if it was an array. You could add to the array, you could remove, you could set, you could get, you could do any of that stuff by implementing this particular interface. And here are the five method stubs. Now offset can be a little confusing, so why don't we rename all of these occurrences to key.

Now offset can be a little confusing, so why don't we rename all of these occurrences to key. Okay, we'll do these one at a time. offset exists. This determines whether or not we have a particular key in our lines collection. And by the way, if we had our lines, we'd be doing something like this, lines[key]. So maybe something like that. How do we determine if that exists? Well, isset(lines[key]).

Well, is set. This lines key. And that's how we determine that. Okay. What about offsetGet? Well, again, this would be if I want to work with my lines object, but grab the second item. Well, what would that be? Well, it would be the second or actually the third item within the lines property that we assign here or field.

Well, it would be the second or actually the third item within the lines property that we assign here or field. Okay. So let's return this lines key like that. Okay. offsetSet. We'll come back to that in just a minute. But offsetUnset. This would be, well, how do you unset a particular item within that array? Well, you can use unset.

This would be, well, how do you unset a particular item within that array? Well, you can use unset. This lines key. Okay. So finally, offsetSet. Yeah, this would be if you want to say lines['foo'] = 'bar'. How would that work? Well, first, we have to figure out, are you setting an explicit key or are you doing something like this? So the general way that you will see this handled just about anywhere is you'll check,

And now it passes. And I think that might be okay, because really, if we didn't implement that, it's going to fail. And if we implement it, but we don't add the necessary methods, we'll get an error. The only other thing you might do is ensure that you implemented it correctly. So we could say this assert, again, instance of Line, and then lines, and grab the first one. Anyways, that would work too. Okay. So now let's change our test to it supports array access.

Okay. So now let's change our test to it supports array access. Okay. So let's run git status. Yep. We'll add those to the staging area. Add lines support for array access. Okay. What next? The next thing I ran into related to preparing our lines for a JSON response.

JSON Encoding the Collection5:18

What next? The next thing I ran into related to preparing our lines for a JSON response. I'll give you an example. Let's copy this. It can render as JSON. And yeah, real quick, once again, one more time, we var_dump our lines, and this is what we get. But what would happen if I want to render that as JSON? json_encode. What would we get?

JSON encode. What would we get? Well, nothing. What about if we instead render the first line as JSON? What do we get? Well, in this case, we do get something. We get the public properties off of line. It's basically get_object_vars. So for example, if we have the first line, you get your object there. If I then said, get_object_vars, this will give us everything that is visible to our

So for example, if we have the first line, you get your object there. If I then said, get_object_vars, this will give us everything that is visible to our current scope or position. And notice we get that. Okay. So that helps. Now, to begin, how can I encode my lines here to make it easy to pass or respond to a JSON request or something like that? Well, let's play around here. Well, one thing we can do is implement the JsonSerializable interface.

Well, let's play around here. Well, one thing we can do is implement the JsonSerializable interface. But first, why don't we make a test to confirm when we've got it working? Yes, I could start with something like this. Once again, it should implement JsonSerializable. And then, well, we might also assert that we have valid JSON. Why don't we start with this, though? So we give it a run and it fails because, of course, we don't yet implement that interface. Okay. At the very top, implement JsonSerializable.

Okay. At the very top, implement JSONSerializable. I will add that method stub, which is jsonSerialize. And yeah, now, if I were to just return foo or something like that, actually, let's do fooBar. Have a look at this. Right here, we will var_dump. And watch what happens if I try to encode the lines now. We run it. And sure enough, we call that method.

We run it. And sure enough, we call that method. Okay. So this is what we want. What if we now return the underlying lines? What would happen there? Run it again. And now we're getting closer. Have a look there. And in fact, if we wanted to configure this, we could then move over to the line object.

Have a look there. And in fact, if we wanted to configure this, we could then move over to the Line object or class and be explicit about how that should be cast. Okay. But nonetheless, we do get green. And we could also do something like this assertJson. So if we were to encode this, we want it to be... Does that make valid JSON? Yeah. It works.

Refactoring into Base Collection8:24

I should have run this test. Yeah. They're at green. Final step is just a little bit of refactoring. You'll notice now we had to implement a bunch of these somewhat confusing interfaces to allow for basic things that you typically take for granted when you're working with Laravel's collections. The side effect is now, in my Lines class, I have so many things that aren't really related to Lines. They're almost more like infrastructure stuff for working with a collection.

to lines. They're almost more like infrastructure stuff for working with a collection. But notice how few of these methods relate to lines. The only ones I see here is this particular one, and then any other ways we might render or sort or map over or filter the lines in the future. So why don't we instead extract a generic Collection class? Or again, pull in an existing collections package for PHP, like the one Laravel provides. We're mostly doing it manually as a learning exercise. It's a good thing to understand on a lower level. Okay.

It's a good thing to understand on a lower level. Okay. So you have your collection. Now this is going to extend collection. And then finally, let's push some of these things up. So let's see. All of this offset stuff, the iterator, the count, JSON serialize. We're going to push all of those up to collection. Here we have a little issue. I'm going to accept that, and then we'll fix it.

Like that. All right. Back to lines. Let's do a reformat, get rid of those unused imports. And notice with this small little change, we've tucked all of that infrastructure code into the collection class. And now my lines class can return to being about what I actually care about in this case. So let's run our tests and make sure I didn't screw anything up. And I didn't. Everything is still passing.

Adding a Map Method10:34

And I didn't. Everything is still passing. So now, let's see if I can show you one other example of lines. Yeah, even things like this. So notice how we use a standard array_map function to create a new collection of formatted lines. Well, what if we instead did something like this? We will formatted lines, and yeah, maybe we introduce a map function. So we're going to map over each line and call lineToHTML. So this might be something we want to offer on our collection.

So we're going to map over each line and call line to HTML. So this might be something we want to offer on our collection. But yeah, right now, of course, that wouldn't work. So let's make it work. On collection, because it's not specifically related to your lines class or your lines collection, it's just something you can do with a collection. So we're going to put it up here. We're going to map. It's going to accept some kind of callable function. We'll just call it function or handler or callable.

It's going to accept some kind of callable function. We'll just call it function or handler or callable. And now here is where we could put the typical array_map code here. So we're going to call this function and feed it all of our underlying items. So now we can either return the results of that, or we could instantiate a new Collection with those items. Let's see what we need here. I run my test, and yeah, that returns green. But yeah, then you'll notice we immediately instantiate a new instance. So why don't we make these immutable?

But yeah, then you'll notice we immediately instantiate a new instance. So why don't we make these immutable? So let's create a new Collection. Okay, so now that's going to return a Collection. If I switch back to lines, I can get rid of that. And then formattedLines, how are we doing? That returns green. I'll inline that and maybe put this below. Really, I don't even think we necessarily need that because it will be called automatically if you try to interact with it as a string, as you see there.

Really, I don't even think we necessarily need that because it will be called automatically if you try to interact with it as a string, as you see there. I'm just adding it to be explicit about what's going on here. We're getting a stringified version of this lines collection. Anyways, I'm just giving you some basic ideas for how you might go about structuring your own code base. So finally, let's run git status, and we'll say git commit with refactor collections. That's fine. And now I'm going to git push this up, and then we'll tag a new release from GitHub. Let's make a new release.

Versioning and Releases13:17

I'll scroll down, and we have our new release. Now the final thing I'll mention here before I let you go is dependent upon your version, you need to be somewhat sensitive about the changes you make to your code. So for example, what if I release 1.0 of this project, a number of people begin using it, and then I make a particular change that would break their code? Well, I will need to consider that, and the version numbers I choose will be very important in that case. And this is where you come into the idea of a patch release versus a minor release versus a major release. A major release typically corresponds to new features and breaking changes.

ArrayAccess InterfaceJsonSerializable InterfaceVersioning

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