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

مرور Phpstan: موارد لبه، جنریک‌های چندنوعی و بیشتر0:00

To wrap up php stent, we're gonna take a look at a few edge cases, how to have multiple generic types, and then a few other functionalities I use on a daily basis. With no further ado, let's jump into the code. On the last last note, we took a look at the collection example, and what's really interesting is Tel RFOs collection also implements that. So if you take a look at collection, you're gonna notice we have a tiki of a key that is,

Map with generics0:24

So if you take a look at collection, you're gonna notice we have a key that is, it must be an integer or a string. And we also have a value and everything within collections is properly typed to ensure we're passing those generic types around. So you can do the same thing with collections. Now what I wanted to start with is a map. I created this class, it's a simple Map class, and we can pass an associative array,

I created this class, it's a simple Map class, and we can pass an associative array, we can get a value from that associative array. We can set a value pretty straightforward. And here we have a map. We just have name matteas and age being the money instance, which should be incorrect. And then we're just saying, get me the name. If I were to run this code, I get matteas, and if I were to run HB 10, it's green.

If I were to run this code, I get matteas, and if I were to run HB 10, it's green. However, I don't want this to be green. I want to be able to type this in such a way that money is not an allowed value. Here's what we can do. We're gonna start by going up here and adding a few templates. We're gonna say we have a T key and we have a T value. Now I'm going to do the same thing to the constructor. This is an array with the key being T key

Now I'm going to do the same thing to the constructor. This is an array with the key being T key and the value being T value. Now let's type the methods key is going to be a T key and it's going to return ATT value. We can get rid of this and we can add a proper type hint here. Now we're creating a map. And now you can type this, right? Let's say that this is a map and this is supposed to be string,

Let's say that this is a map and this is supposed to be string, string, something like this. Now if I run this, you may notice a php stand is going to pass, and that is because php stand has a hard time connecting the dots. Here we're instantiating a class and we're passing an array and we defining what that class should look like or passing that. It should take a string and a string.

Typing via function hints2:04

that class should look like or passing that. It should take a string and a string. But php stand has a really hard time referencing that. So this in match case, and there are a couple of things you can do in those situations. The first one is even though we cannot properly type this $map variable, if we were to have a function that says, let's say processMap and it takes an instance of Map and we're just gonna echo $map->getName(),

let's say processMap and it takes an instance of Map and we're just gonna echo map, getName, something like this, and now we can get rid of this and we can call processMap. What we can do here is we can type this guy. So we could say, this is a Map and this should be string string. Let's get rid of this and add a proper type hint. And now php send is going to complain about it. If I were to go ahead and fix this

And now php send is going to complain about it. If I were to go ahead and fix this and say 27 as a string, now we're green. If I were to pass 27 as an integer, we're back to add. So even though we cannot type the variable itself, if you will, if it's being passed methods, we can still ensure that the methods take the right values. Another way we could handle this is I'm going to get rid of this type hint. Actually, let's live this here. I'm actually gonna remove

Alternative map construction3:10

get rid of this type hint. Actually, let's live this here. I'm actually gonna remove this method call here is we could instead, and I don't particularly like this approach, but it's possible we could have this be a private constructor. We're not gonna take anything and we're simply gonna have a property here that says data and it starts off as an MTRA. And here we can say tiki T value, let's get rid of this.

and it starts off as an MTRA. And here we can say tiki T value, let's get rid of this. And then instead of passing an array, we can just set things by calling math that you could say map is going to be a new map. And then we're gonna do map.set(name, Mathias), and then map.set(age, 27) like this. And then we can properly type this guy. So we can say map: string string, and let's run this. So as you can see, we have a problem right here.

So we can say map string string, and let's run this. So as you can see, we have a problem right here. We expect a string, but we're passing an intro. If I were to turn this into a string, we're back to green. We could also make another improvement here by saying that T key should be array array key. Let's rerun php stand and regreen. So there are some edge cases and some subtle limitations to what you can do with PHP stand, but in general, it is really,

Enum and valueOf typing4:21

and some subtle limitations to what you can do with php stand, but in general, it is really, really straightforward and really powerful. Let's take a look at a few other functionalities from php stand that I use on a daily basis. Okay, so here's an example. Let's say that we have an enum and we have a function. For example, you're processing a webhook, so data is coming raw to you and you want to hydrate something into an enum.

so data is coming raw to you and you want to hydrate something into an enum. So you probably see something like status, we're gonna create a status from a value, something like this. And maybe you're just passing those arbitrary strings. Something you can do with php stand is, first of all, we can give this array a shape. So we could say status. And here's where things get tricky. Uh, we cannot say that this is an enum because it isn't.

So we could say status. And here's where things get tricky. Uh, we cannot say that this is an enum because it isn't. It's going to be a string. And we also cannot just say it is a string. I mean we can say it's a string, but it's not as for precise. So if it were to say this is a payment status and we're passing the string, let's see what happens if I run php stan. Okay, so we expect an enter string payment status given we

what happens if I run php stand. Okay, so we expect an integer paymentStatus given we cannot convert to a string. And on 1 67 we expect array status, paymentStatus, but we gave it statusFull. So this is not good enough. Of course, if we were able to pass a hydrated enum, that would be great, but if for example, you're processing a web hook or something of sorts, you'll get the raw value,

you're processing a web hook or something of sorts, you'll get the raw value, you get a string, we could pass it as a string and let's try this. Let's see what you get. We're green, but now we can pass any string and then this can fail. So here's what you can do. We can do valueOf and we can pass an enum here. So let's say paymentStatus, whoops, like this. And now if I try to run phpstan,

So let's say paymentStatus, whoops, like this. And now if I try to run php stan, it is going to complain about it. So it automatically gives us a union of strings. It can be failed, succeeded. And as we add more cases to this enum, it will increase it as well. If we say retried and we rerun php stan, you can see that it now includes retried as well.

and we rerun php stand, you can see that it now includes retried as well. So if we just pass something that's valid here like this, it is going to pass. You can also do this with constant. So let's say we have a paymentMethods constant, and ideally this would be an enum, but maybe you still have those in your code base. What you can do here is, let's say something like this. We have stripe and we have bank.

What you can do here is, let's say something like this. We have stripe and we have bank. So let's call this bankTransfer. And now let's just refactor to this a little bit. We're gonna take a method and a displayName, something like this. Let's get rid of this. And now in processPayment, we're just gonna pass, for example, I'm gonna say bank, and then we're gonna add a type.

for example, I'm gonna say bank, and then we're gonna add a type. I'm gonna say bank transfer like this. And let's just add, call the method, a line break. And that displayName, if we were to run our code, we can see that it's being spit out correctly. And if we run php stand, it is also passing. However, this should not pass because this is a typo. So here's what we could do. We can say this is going to be a kio and we're not within any class context.

So here's what we could do. We can say this is going to be a kio and we're not within any class context. So we're just gonna see payment methods, and this is going to be method. And then we're gonna do value of this is also going to be payment methods, and this is going to be display name. So if we try to run php artisan now it's going to fail. It should be bank transfer, stripe, and we're giving it bank transfer. So if we just fix this, we are back to green.

Literal and refined types7:45

and we're giving it bank transfer. So if we just fix this, we are back to green. This is a very specific, very niche usage nowadays, especially as we have Enos, but it still could be useful for you. And finally, we have literal types. So let's make a function called makeRequest for example. And this is going to take a method. Again, you probably wouldn't use this if you have Enos in place.

Again, you probably wouldn't use this if you have Eno in place. And let's do it. That's going to return void. And we're just gonna say making method request. You know, let's add one more thing here. Let's do, we're gonna take an ID as well or ID and let's add a line break here. And now you can say something like, make requests. We're gonna make a post request to ID 1, 2, 3, right? Let's try this and let's see what we get.

We're gonna make a post request to 1, 2, 3, right? Let's try this and let's see what we get. Let's run php here and let's get rid of this actually, just so we have a clean state making post requests for 1, 2, 3. That looks good. Now, what if we were to pass something like this? This is incorrect, but the code still runs, and php send doesn't tell us anything. So what we could do is let's add a docblock.

and php send doesn't tell us anything. So what we could do is let's add a doc block. And here in string here in method, we're gonna do get, post, put, patch and delete. So we're literally just telling php, send what the acceptable values are. In those cases, they're all strings. And let's rerun this. The code runs, that's what php send says. Now we're saying that may request expect, delete, get, patch, post or cut.

Now we're saying that may request expect, delete, get, patch, post or put. And we gave it posts with cts pretty similar to what we did with key and value of. Okay, so let's fix this, let's make this post. Let's rerun php artisan serve and back to gray. Now what if we were to pass something like -1, 2, 3? Well, php sends passes, but this is also completely incorrect. So something we could do is we could say this is a positive.

but this is also completely incorrect. So something we could do is we could say this is a positive end and if we were to run a php stand, you can see that it is now complaining about a 1, 2, 3. Again, not a lot of usage since we have enums, but in some cases where you have to take strings, if you can limit them to a specific set of strings, that's much more predictable. Okay, to wrap this up, let's see what we can do when we have to pass fully qualified name spaces for classes.

Class-string subtype checks9:54

Okay, to wrap this up, let's see what we can do when we have to pass fully qualified name spaces for classes. Let's take a look at this example. We have this PaymentProcessor interface. Then we have a Stripe implementation, and we have a PayPal implementation. For some reason, we want to pass a string with the full qualified namespace for the class. So for example, we would do something like this and let me just add a line break so it's easier.

So for example, we would do something like this and let me just add a line break so it's easier for you all to see what's going on here. We just call into something with paymentProcessor and pass in Stripe class. If you don't dunno, what the syntax does is it just gives you the full qualified namespace for a class. So if you had, for example, a User model and you were to use your class, it would spit out something like this pretty handy.

and you were to use your class, it would spit out something like this pretty handy. So here's the problem. If I were to run this, this is obviously going to work. And if I were to pass instead something like money, it is going to fail because of the type system. Let's run this. It clearly fails. Now this one failed on construction, but even if it were constructable, it would fail because of the type hand.

but even if it were constructable, it would fail because of the type hand. It needs to be an instance of PaymentProcessor. However, you cannot know ahead of time that this is going to fail. With php send, you can. So here's what you're gonna do. Let's revert this back to stripe. And we're gonna type hand the skyRate here and we're going to say this is going to be class string. And now we're gonna pass paymentProcessor here.

and we're going to say this is going to be class string. And now we're gonna pass payment processor here. So this has to be a class string of a class that implements payment processor or is a subtype of payment processor. Now let's run php stand. Whoops, there we go. Green. And if I were to pass, for example, money instead, php stand will fail. We expect a class string of payment processor. We gave it a regular string.

We expect a class string of PaymentProcessor. We gave it a regular string. Now, if I were to just say that, expect a class string here like this, and I were to pass something like fubar, let's run this. You can see that it also fails. It expects a class string and re passing that string. If we expect something like money here again, it is going to pass. And that's because it is a valid class string.

money here again, it is going to pass. And that's because it is a valid cluster string, even though it is not a subtype of paymentProcessor. So let's just go back here and re add our type. Now we're telling php stand that this method, it's gonna take the full qualified namespace for a class and the class must be a subtype of paymentProcessor. Let's rerun this. Okay, we're failing. Now let's fix this. Let's say we want to pass stripe here.

Now let's fix this. Let's say we want to pass stripe here and there we go back to three KHP Stand is a great tool. It has a lot of types, it has a lot of roles, but I can tell you that in real life, you're probably gonna use a fraction of its capabilities and that's fine because it means that a small percentage of its functionalities cover most of the cases. And then if you have some edge cases or some niche cases, maybe there's also a php percent

And then if you have some edge cases or some niche cases, maybe there's also a php percent type to cover you for that. For example, positive integer. That's not something I use frequently, but when a situation comes where you need a positive integer, that type exists. And I can use it to tell PHP sent about that. I hope you all enjoyed this lesson and I see you on the next one.

I hope you all enjoyed this lesson and I see you on the next one. Bye.

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