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

Introducing PHPStan0:00

Let's take a quick break from coding and patterns and whatnot and talk a little bit about tolling. And the tool I wanted to start with is phpstan. PHPStan is a static analysis tool. And if you don't know what static analysis is, it's basically a way to analyze your code at static time without actually executing it. So PHPStan allows you to find bugs and find things that shouldn't be happening in your application without

and find things that shouldn't be happening in your application without actually running the php code. It is one of my favorite tools in PHP. It is super convenient. You can run it in CI just before your task, for example. And it also supercharges PHP type system. For example, you may know that PHP does not support generics by default, but it does support generics through PHP study. You know, PHP does not support typed arrays,

by default, but it does support generics through PHPStan. You know, PHP does not support typed arrays, but it does support them through PHPStan. As we've spoken on the scores when it comes to associative arrays with PHP, we just cannot assert that it has a given shape, but that's also something we can do with PHPStan. And the easiest way to tell you about PHPStan is to actually show some code and go through it a little bit. Okay, the first thing we have to do is to install PHPStan.

Installing and Playground1:02

to actually show some code and go through it a little bit. Okay, the first thing we have to do is to install php stand. So let's run composer require phpstan/phpstan-dev. There we go. It is installed. And now I've created a file called phpstan.php under app, and this is just going to be our playground for now. And I've added some code. We're gonna go through it together.

Running Analysis via CLI1:30

And I've added some code. We're gonna go through it together. For now, I'm just gonna say echo. We are here and return early. Now if we run this file, we should see we are here. And the question now is how do we run php stand for now? We are going to run it through the CLI, let me show you. We're gonna say vendor/bin/php artisan analyze. And we're gonna pass a path, either a directory or a file.

We're gonna call it the analyze command. And we're gonna pass a path, either a directory or a file. So I'm gonna say app php, send app php, let's run it. No rules detected. That's because we have to pass a level to php send. So we can say something like level 5 and it already found an error. We have some debt code. So line 31, let's see what you have at line 31. Yes, we have a bunch of code that's not going to be executed.

So line 31, let's see what you have at line 31. Yes, we have a bunch of code that's not going to be executed because of this return statement. So let's remove the return statement and then let's just remove all of the calls and rerun php set. And now we're back to green. Okay, running this entire command all the time is a little bit annoying. So let's fix that. We're gonna create a

Creating PHPStan Config2:32

the time is a little bit annoying. So let's fix that. We're gonna create a php send config file. To do that, we're going to create a file called php.ini at the root of your project. Let's jump into that file. And now let's write some configuration. So we can say parameters, paths. And here we can specify in which paths we want php send to run.

And here we can specify in which paths we want php sent to run. For now, we wanted to run specifically in a single file. So let's say app, php stand or php. And then we can also specify the level. Let's say that we want it to run on level 5. Now if we just run vendor/bin/php stand, it will use the configuration file we have defined. Great. Let's go back to our playground and let's start playing with it.

Great. Let's go back to our playground and let's start playing with it. Imagine you're working on a hot fix and you're just sharing some code and post your production real quick. Now imagine you did something like this, you inverted the order of parameters on this Invoice class. We expect a Money value object as the amount and a recipient, which is a string as the second argument. But what if by mistake we pass it the other way around?

and a recipient, which is a string as the second argument. But what if by mistake would pass it the other way around? You can see that my IDE is already screaming at me, but it can still push this. I can still commit this and this code obviously is going to fail if we run php app php, standard php, you can see fails, but it can still push this. Now if I run php stand, you can see that php stand is telling me that the first perimeter is incorrect.

that php stand is telling me that the first parameter is incorrect. We expect a Money instance and we gave it a string. And the second parameter is also incorrect. We expect a string and we gave it a Money instance. Now this is a pretty silly example, but it's also a real example that happens all the time. Someone's working on a hot fix, they don't go through the code, they don't run the code, they don't run all of the tasks.

Typed Arrays with Docblocks4:20

through the code, they don't run the code, they don't run all of the tasks and something goes into production. This allows you to catch some bugs very early on. Let's do this. Let's rerun phpstan and make sure we're back to green. And we are. Now let's actually cover some of phpstan's type features. Now remember I mentioned that phpstan gives PHP type systems some extra power.

Now remember I mentioned that php stand gives php type systems some extra power. That's my favorite thing about php stand or one of my favorite things, and that's what I want to cover in this video. So on this video we're going to cover two php stand features. The first one is typeErase, which is super, super useful. And if you haven't seen it yet, I'm sure you missed it without even knowing about it. And the second one is arrayShapes.

I'm sure you missed it without even knowing about it. And the second one is array shapes. So let's, let's jump into some code here we have an array of invoices and those are just Invoice objects. And here we have an array of recipients and then we have this emailInvoices function that takes an array of invoices. We go through each one of the invoices and we just echo some text. So if I were to call this

and we just echo some text. So if I were to call this and say that I want to email some invoices and pass this array of invoices, if I were to run this code, okay, let's get rid of the, we are here and let's rerun this. We're sending an invoice to Mateos, one to Jeffrey, and one to Taylor. Perfect, that works. Now, if I were to instead pass by mistake recipients here,

Perfect, that works. Now, if I were to instead pass by mistake recipients here, this code is not gonna work. See, and this code's not gonna work because we're trying to access properties that did not exist on that object. So this is actually the happy path scenario. Your code just doesn't work. Now notice that until this point, until we try to call sense and no, the code is still running,

Now notice that until this point, until we try to call sense and no, the code is still running, we're getting some warnings, but the code is still running. So this is the sort of lucky mistake. Your code is gonna crash, it's fine. In some cases when you pass the wrong argument, you can actually have much worse situations. As you know, php does not allow us to tell what's inside an array. For example, I would love to say that this array

to tell what's inside an array. For example, I would love to say that this array of invoices should only contain Invoice objects. And you know, maybe you could do something like this. We could say assert that invoice is going to be an instance of Invoice. And if I try to run this code now it is going to crash very early. That assert is going to fail. But that depends on you always making sure

That asserts going to fail. But that depends on you always making sure you call the assert method. And it does not give you all your ITE information on what to post to be sent. So with php stand, we can do something very cool. And php stand depends heavily on doc blocks. Here's what I'm gonna do. I'm gonna add a doc block here and where it says perm array, that's still very generic, doesn't tell us exactly what we're supposed to receive.

and where it says perm array, that's still very generic, doesn't tell us exactly what we're supposed to receive. I'm gonna do brackets and now I'm going to pass first what I expect the key to be and expect the key to be an integer. And then I expect the value to be an instance of Invoice like this. And you can see that my IDE is already complaining. We expect a perimeter type array of Invoices, but we provided an array of recipients.

We expect a perimeter type array of invoices, but we provided an array of recipients. And now if I were to run phpstan, phpstan is telling us that we expect an array of invoices, but we're giving it an array of recipients. So this would be caught very early on CI. Now there's also a simpler syntax for this. We can tell php stand what to expect as the key. For example, if this were an associated array, we could say they expect a string.

For example, if this were an associated array, we could say they expect a string. But for lists, for ordered arrays, we can simply say something like this. We could either say that we expect a list and do [] and pass the follow qualified namespace of the object and we're gonna get the same result. Or we could do something like this. We could say that we expect an Invoice and we can do square brackets to tell php send.

We could say that we expect an invoice and we can do square brackets to tell php send. This is supposed to be an array. There is a slight difference between those options. One being that when we say the list, we're telling php send. We expect an ordered array that is a pure array. And when we say something like array and an invoice, we're just telling php send that the key should be an integer. We're not telling it whether it should be ordered or not.

that the key should be an integer. We're not telling it whether it should be ordered or not. For example, for now, let's go with square bracket, something like this. Now php stand is telling us that this parameter is incorrect. And you can see that my ID is also complaining about it. Most modern ID with intelligence are going to understand PHP syn types. So in this case, PHPStorm is already telling me

to understand php syn types. So in this case, PHPStorm is already telling me that this code is wrong, but if I were to miss this warning, it would fail on CI or it would fail when it were to run the test locally. So let's fix this. Let's say invoices. Let's rerun php vendor/bin/phpstan and re back to green. Now let's try something. What if I remove the docblock? Would phpstan so pass? And it does. So that has to do with phpstan levels.

Would php send so pass And it does. So that has to do with PHP send levels. You're gonna have to check the documentation to see what each level does. But at level five, PHP send does not require a raise to always be typed. So if we were to go to pb_send.php and increase this to level six and rerun php send, you can see that it now is complaining about invoices not having enough

and rerun php stand, you can see that it now is complaining about invoices not having enough value typed specified. So at level six we are required to have those stock blocks. Let's re-add it and rerun it. We can get rid of this one, it doesn't add any value. Let's rerun this and we're green. Okay, so that's it. Four types arrays at least for now. Now let's take a look at array shapes. Imagine the following, you have a price config function

Array Shapes and Optional Keys9:48

Now let's take a look at array shapes. Imagine the following, you have a priceConfig function and it takes a config as an argument. And we're just going to echo the config['host'] and we're going to echo the config['username']. And now we're going to create a config array. Associative array. We're going to say the host is localhost and the username is root. If we were to call pasteConfig and pass this config we created, let's run our file.

If we were to call pasteConfig and pass this config we created, let's run our file. And you can see it outputted, localhost in root. So it is correct. Now what if we forgot about this username right here and we were to run it? Well, you can see we got a warning, which is not an error, so it does not crash our program, but we have a problem here. So we can also tell php stand.

but we have a problem here. So we can also tell php stand. What do we expect when it comes to an associative array? Here's what we can do. We're gonna add a dock block and here in array we're gonna add curly braces. And we're gonna say we expect a host key, which is supposed to be string and we expect a username key, which is also supposed to be a string. We can rid of this return and let's rerun php stand. And you can see that. Now php stand

We can rid of this return and let's rerun php stan. And you can see that. Now php stan is complaining about that. We expect an array with host as a string, username as a string, but we gave it an array with host as a string. That's all. So let's fix that. Let's say that the username is root and weran this, and now we are back to green. We can also combine type arrays, array shapes. Remember that we can pass anything

We can also combine type arrays, n array shapes. Remember that we can pass anything to a type three including N array shape. So if instead of receiving a config, we were to receive multiple configs, for example, we would receive multiple configs, we would iterate on each one of them and now we have to update the type. We could say something like this, we could say that we expect an array with integer with keys

We could say something like this, we could say that we expect an array with integer keys and this array shape as a value. And you can see that in my, I is already complaining about this, so let's run php. Since it is failing as expected. I'm just going to wrap it as an array. And we're back to green. And then we can also use the same syntax we were using for arrays. We can just add square brackets at the end.

syntax we were using for arrays. We can just add square brackets at the end. So we're telling php send that ConX is supposed to be an array of this, which is in a array shape. Let's undo that and go back to what we had. Let's make sure we're still green. And another nice that we get with those annotations is auto completion. So if forward type config age, you can see it auto completes to host.

So if forward type config age, you can see it auto completes to host. If our type U, we get username. And if I were to add something new, like full is going to be an integer and I were to say F it auto completes with full. So that's pretty cool. We can also tell php, send that some keys are optional. For example, we could do something like password is going to be string, but this question mark indicates it might not be always available.

to be string, but this question mark indicates it might not be always available. So if I were to do something like this, let's echo this and let's add a line break here and I rerun a php stand, let's increase the level. Let's do something like nine. Notice that at higher levels it's also complaining about this offset password, not always existing. So we would have to do something like this if our $A key exists, key being password

So we would have to do something like this if our A key exists, key being password and r, a being config. In this case we went to Echo and if I rerun php stand now it is passed. And so even things like those here we're specifying their password is not always available, but on our code we're always expecting it. PHP send can also catch those things. If we run this on level six, it will not catch that.

php send can also catch those things. If we run this on level six, it will not catch that. So let's go back to what we had. If I were to run php stand, you can see it screen. But now if I run our code, you can see we got a warning because password is not always defined. Let's get rid of this and we're back to green. Now, the auto completion niceties also work for type array. So you can see my ID understands that an invoice is actually an instance of Invoice.

So you can see my IDE understands that an Invoice is actually an instance of Invoice. And if I were to do invoiceRecipient, I have proper auto completion. If I press go to definition, it takes me to the definition. Same thing with the methods. So as long as your IDE can understand those more complex types, you're also gonna have much better auto completion. On the next lessons, we're going to cover a few extra features of php stand, one

On the next lessons, we're going to cover a few extra features of php, one of them being generics, which is super useful in the future. Many of us will love to have on php. While it's not in php, we have access to it via php set. And we're also going to cover how to integrate php send with Flare file. As usual, I hope you enjoyed this lesson and I'll see you in the next video. Bye.

and I'll see you in the next video. Bye.

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