5/28/2023 0 Comments Locad a class definition in php![]() ![]() They allow you to describe more specific types coming to and from functions and methods. ![]() ![]() Now that you understand what generics are for, it’s up to you to come up with possible uses inside the codebases you work with. $generator -> getReturn ( ) // Bar Your turn! # $generator -> send ( 1 ) // wrong, expects Foo Yield 'foo' => new Foo ( ) // wrong key and value On the other hand, if we implement DogFeeder with a more general type than a Dog, let’s say an Animal, we’re fine: class AnimalFeeder implements DogFeeder But since we’re still writing a lot of types in PHPDocs only, static analysis has to check for these errors. If we pass the BulldogFeeder into the feedChihuahua()function, the code would crash, because BulldogFeeder::feed() does not accept a chihuahua: class BulldogFeeder implements DogFeederįeedChihuahua ( new BulldogFeeder ( ) ) // □įortunately, PHP does not allow us to do this. If we implement a BulldogFeeder that narrows the parameter type (it’s covariant, not contravariant!), we have a problem. $feeder -> feed ( new Chihuahua ( ) ) // this code is OK ![]() Let’s say we have an interface called DogFeeder, and wherever DogFeeder is typehinted, the code is free to pass any Dog to the feed method: interface DogFeederįunction feedChihuahua ( DogFeeder $feeder ) When we describe a type being covariant it means it’s more specific in relation to its parent class or an implemented interface.Ī type is contravariant if it’s more general in relation to its child class or an implementation.Īll of this is important because languages need to enforce some constraints in parameter types and return types in child classes and interface implementations in order to guarantee type safety. Covariance and contravariance describe relationships between related types. There’s one more use case generics solve, but first I need to explain these two terms. If we don’t want our class to be generic, we only use the latter tags: /**Ĭlass DogCollection implements Collection Preserving the genericness is done by repeating the same tags above the child class and passing it to and tags: /**Ĭlass PersistentCollection implements Collection Specify the type variable of the interface/parent class.Preserve the genericness of the parent, the child class will also be generic.When implementing a generic interface or extending a generic class, you have two options: The types of the Collection can be specified when you’re typehinting it somewhere else: /** We can also put above a class or an interface: /**Īnd then reference the type variable above properties and methods: /** Up until this point, I’ve written only about function-level or method-level generics. Marking the return type as T(for example for a findAll()function) would infer the return type as an array of Articles. If you then call findEntity(Article::class, 1), PHPStan will know that you’re getting an Article object or null! If you want to involve a class name in the type resolution, you can use the class-string pseudotype for that: /**įunction findEntity ( string $className, int $id ) In some situations the PHPDoc tag can be used instead. Only objects of classes extending Exception will be accepted and returned by this function. You can also limit which types can be used in place of the type variable with an upper bound using the of keyword: /** The type variable name can be anything, as long as you don’t use an existing class name. Consider a function that returns the same type it accepts: /** In PHPDocs we annotate them with the tag. Other languages that have generics also use this term. These rules are defined using type variables. They offer generating infinite number of signatures for functions and methods based on rules developers can define themselves. It’s not enough information to keep the code type-safe. finds and returns an entity object based on $className If you have a function that returns different types based on argument types passed when calling the function, you’d have to resort to returning a union type, or a more general type like object or mixed: function findEntity ( string $className, int $id ) : ? object So we declare that the function accepts an argument of a specific type, and also returns a specific type: /** When we’re declaring a function, we’re used to attach a single signature to it. Also check out practical examples in the Generics By Examples article. ![]()
0 Comments
Leave a Reply. |