php

Typed Properties In PHP Are Neato

shelob9

Josh Pollock

Posted on February 1, 2020

Typed Properties In PHP Are Neato

Until recently, for a PHP and JavaScript developer, avoiding bugs caused by variables being the wrong type was difficult, beacuse the langues are not strongly-typed. Thanks to PHP7 and TypeScript, we can opt-in to more type safety, which I like.

PHP7 added scalar type hinting to function parameters, as well as return types. This makes the getter and setter pattern very useful. By protecting a property and a protected property, we can prevent a property from being set to the wrong type -- from outside of the object's scope. This pattern looks like this:

class User {
    /** @var string */
    protected $firstName;

    public function getFirstName(): string {
        return $this->firstName;
    }
    public function setFirstName(string $firstName) : string
    {
        $this->firstName;
        return $this;
    }
}
Enter fullscreen mode Exit fullscreen mode

That's cool, and while it's a lot less boilerplate than it would be in PHP5, it's still a pretty complex way to implement a string property on an object. This class has two public methods that need test coverage, which adds up.

Having a property that acts public, but also is constrained by type, is nice. I think the popularity of Laravel backs up this opinion. And yes, I can use magic methods to make something like a Laravel model.

Also, PHP 7.4 has typed properties and they are neato.

Refactoring PHP With Typed Properties

So, I can now rewrite that class, with no methods:

class User {
    public string $firstName;
}
Enter fullscreen mode Exit fullscreen mode

In addition to being less code, I don't need to write a test for this. However this class gets used in integration tests by other classes, my IDE and a static analysis tool all prevent it from being used wrong.

In the first example, nothing stopped me from setting $firstName to an array from another method of this class. Now the program will not let me make that mistake. Machines are better at remembering stuff than me, so that's great.

But Wait. There Is A Catch!

One catch though, Ok, technically, it's a potential error that you can catch...

You can not read a property before it is set for the first time:

//This works
$user = new User();
$user->firstName = 'Roy';
echo $user->firstName;

//This throws an error
$user = new User();
echo $user->firstName;
Enter fullscreen mode Exit fullscreen mode

This problem is also present in the older method. In both cases, a default value of the property could be set. Or I could just not use the property before setting. Depends on how the program is run. I don't like the possibility of the code being used wrong, beacuse lots of people I don't know run code I write.

One solution is to hardcode the default value:

class User {
    public string $firstName = 'Roy';
}
Enter fullscreen mode Exit fullscreen mode

That keeps the code minimal, which is nice. I do think writing the class so that the property HAS to be set on initialization is a good option as well:

class User {
    public string $firstName;

    public function __construct(string $firstName)
    {
        $this->firstName = $firstName;
    }
}
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
shelob9
Josh Pollock

Posted on February 1, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related