Buy

PHP 7 added scalar type-hinting. But it also added - finally - return types. These didn't exist at all in PHP 5, not even for objects. This gives us the ability to say that this method returns a string and that method returns some object. I love return types.

Start in GenusController: let's fix our code first. Say $genus->setName('Octopus'). Now, dump $genus->getName().

156 lines src/AppBundle/Controller/GenusController.php
<?php
declare(strict_types = 1);
... line 3
namespace AppBundle\Controller;
... lines 5 - 15
class GenusController extends Controller
{
... lines 18 - 20
public function typesExampleAction()
{
$genus = new Genus();
$genus->setName('Octopus');
... line 25
var_dump($genus->getName());
... line 27
}
... lines 29 - 154
}

We know that this should return a string... but technically... it could return anything. Like, what if we get crazy and just return 5.

225 lines src/AppBundle/Entity/Genus.php
<?php
... lines 2 - 3
namespace AppBundle\Entity;
... lines 5 - 17
class Genus
{
... lines 20 - 97
public function getName()
{
return 5;
... line 101
}
... lines 103 - 223
}

What happens? Well, no surprise... it returns 5, an integer. Yep, we have a method that should return a string, but is instead returning an integer. Lame!

Adding a Return Type

To fix this, add a return type. After the method name, add : string. Of course, this could be any type: a class name, int, bool, float, array, callable or even the new iterable. More on that later.

225 lines src/AppBundle/Entity/Genus.php
<?php
declare(strict_types = 1);
... line 3
namespace AppBundle\Entity;
... lines 5 - 17
class Genus
{
... lines 20 - 97
public function getName(): string
{
... lines 100 - 101
}
... lines 103 - 223
}

As soon as we do this, PhpStorm is furious all over again! And so is PHP: refresh!

TypeError: Return value of getName() must be of the type string, integer returned

Return Types & Weak Versus Strict Mode

Yes! There is one really important thing happening behind the scenes: this throws an error only because this class is in strict mode.

What I mean is, if we changed Genus back to weak mode, then instead of throwing an error, PHP would try to turn the integer 5 into a string. The strict or weak mode affects argument type-hints and return types.

But here's the tricky part: in this case, the strict_types, that's important is the one in Genus. If you remove the declare(strict_types=1) on Genus and then refresh the page... it works!

Wait, wait, wait. When we type-hinted the argument in setName(), that caused an error when we put the controller in strict mode. But when we added the return type, suddenly it was important to use strict mode in the Genus class.

Here's the real, full explanation. When you add strict_types=1, it says:

I want "strict" type-checking to be applied to all function calls I make from this file and all return types in this file.

Or, to be even more brief:

I want "strict" type-checking to be applied to all values I control in this file.

The return value of getName() is something that we control and calculate in Genus. Thanks to the strict_types in Genus, PHP forces us to write good code and return the correct type.

But, with setName(), the argument value is being created outside of this class in GenusController. For that, the strict_types needs to be added there.

Actually, scalar type hinting and return types are really easy... except for the strict_types part. My advice is this: start adding a few strict_types to your code and see how you like it. It's a great feature, but your code will work fine with or without it.

In Genus, let's fix our code by returning $this->name. Now, life is good.

224 lines src/AppBundle/Entity/Genus.php
<?php
... lines 2 - 17
class Genus
{
... lines 20 - 97
public function getName(): string
{
return $this->name;
}
... lines 102 - 222
}

But what if Genus did not have a name yet? In that case, getGenus() would return null. Is that allowed? Nope! null is not a string... and this can be really annoying. Fortunately, PHP 7.1 gives us nullable types.

Leave a comment!

  • 2018-02-21 Patrice Duchamps

    weaverryan Thank you so much for yet another great post. In regards to type hinting in php 7, sometimes in our entity we don't want a variable to accept null - and when using the form component, it will trigger an error exactly like this:

    https://stackoverflow.com/q...

    The proposed answer suggests to always use a Data Transfer Object (DTO), and reading the sources mentioned, they suggest an entity should not be in invalid state. May I ask your opinion about this? Not sure what you think I don't think this is feasable as it would be very difficult to handle DTOs with OneToMany relationships for example, as one would have to map the entity and all its relations to the DTO - and for something like an update, I can't see how this would be realistically doable - isn't that just plainly impossible to use with Doctrine ORM and Symfony form component?

    So do you guys at KNPU personally use DTO (which would solve the type hinting issue)? Using DTO seems impossible to update entities with OneToMany relationship for example, or am I missing something.. Thank you!

  • 2018-01-29 weaverryan

    Hey Juan Luis Garcia!

    Yea... this is *not* possible. The reason is that, as we learn about in this tutorial, it's up to the author of each file to decide if they want to have strict_types=1 for that file. Then, they write their code accordingly. If there *were* some way to do it globally, PHP would apply it to *all* files, including third-party vendor files, which weren't expecting that behavior. And since there's no way for PHP to know *your* files versus *their* files, it all just kinda doesn't work :). So yea... annoying. My best advice - which you probably already thought of - is to update your PhpStorm (or whatever editor) to automatically add that line when you create a new PHP file / class.

    Cheers!

  • 2018-01-27 Juan Luis Garcia

    Hello!

    Can I configure the strict_types=1 in all my project? I don't want to put strict_types=1 in each file.
    Is it possible?

    Thanks!