So everyone is talking about this hip “new” kid on the block for PHP: Generics. The RFC is on the table and a lot of people are getting all excited about it, but you don’t fully see the excitement? Let’s explore what it’s all about!
What is the use case of a Generic?
The basic idea is that you can reuse a class that is statically typed with different type parameters. OK, I understand that this might sound very confusing. So let's check out an example:
Yes I know, I’m explaining OO stuff with a car class. I know it’s super cliche, and I’m normally not a fan of getters, but just roll with it.
As you can see, we are creating a Car object with 2 parameters. The wheels and the engine. Now, this is all fine and dandy, but what do $wheels and $engine parameters represent? In this case, it’s the number of wheels and what engine it sports one would assume, as we send an integer and a string along.
But $car = new Car(‘pirelli’, true); would be just as valid.
This is of course one of the typical things of a dynamically typed language. But if we want to add some more uniformity in our class we could, thanks to PHP 7 and types:
Now it’s impossible to create an invalid object thanks to the strict types. OK cool, let’s make everything strictly typed then!
But what if we want to create an object that’s both statically and dynamically typed? This sounds absurd but let me give you a use case. You want an object that accepts a parameter on creation but it needs to always return that same type of parameter on its return.
So for example when I do $myCar = new Car('honda'); and later $myCar->getEngine(); I want to be sure that what I get back from getEngine is the same type as what I’ve put into the constructor (in this case a string).
OK show me this generic magic then!
Well… the thing is… at the time of writing, generics don’t yet exist in PHP yet. I know… what a tease. But luckily for us there is an RFC! So people are still loudly arguing whether or not they want to include generics into PHP and how it should look. But let us take a look at what the current proposed way of doing it is.
The use case described above could look like this:
As you can see, we now have brackets! So first up is this:
$car = new Car<int,string>(4, 'Honda');
Here we say, we are going to create a new Car, with 2 parameters; an integer and a string. You could according to the currently proposed RFC just send:
$car = new Car(4, 'Honda');
but I like the explicit version better for explanation sake. Next up is:
class Car<WheelType, EngineType>
This tells the class about what variable types it supports. And then we can use these virtual types just like normal types in the class. So in this case the WheelType will be an integer and the EngineType a string.
It’s as easy as that.
That’s a use case that will never happen!
It is indeed a niche use case, but as PHP grows towards a hybrid of a dynamically typed and strictly typed language it does make sense to include some more features of strictly typed languages. While true, you will not use this every day, there is no harm in having it in the language. It would however be handy for people that write logging or collection packages. Take this piece of code for example:
You can now reuse this collection for whatever you want, but you will always be sure getValues() will return a collection of items that have the same type.
Even more fun is that you can instantiate a Collection like this: $collection = new Collection<Runnable >(); where Runnable is an interface. This way you could have, for example, a collection that you are sure of only has items with values objects in them that conform to the interface. For example:
The <T is Runnable> in this context would stand for: "you can enter whatever type you want here, but it has to adhere to the Runnable interface."
So what’s next? As I said before, the proposal is currently in draft. Once the proposal is finished it will go into a voting round and if there is a consensus about implementing it, it will be added, otherwise it’s back to the drawing board for Generics in PHP.
p.s. you can follow along with how the RFC is going here