zmrd

daily occasional dose of nihilism🌗

Typed properties

PHP 7.4 is out and everyone seems to be happy about the typed properties.

I’m not. Don’t get me wrong, having an option to enforce property type and presence is a good thing, I won’t argue on that one. But every feature will eventually get misused and this is especially true when it comes to PHP developers. Every time there’s a discussion about PHP 7.4, I hear people saying things like: „We can finally get rid of that getter and setter boilerplate!“

Can we, though? When it comes to accessors in general, I’m the very last person defending it. I hate getters and setters, I truly do. It’s one of the reason I hate Java so much. I don’t like writing it and using it. But typed public property isn’t the answer.

Consider this:

class Product
{
    public float $weight;
}

So, how about this one? We don’t want $weight to be a non-positive number. How to deal with that? Yeah, you have to make it private and write an accessor for it. Sure, it could be an immutable property (so you need a getter for it anyway), or you could use a magic access, which, however, you can already do prior to PHP 7.4.

Think of an existing class exposing a public property. Later in the development process, you might want to restrict the value somehow. In that case, you have to introduce magic access support, unless you’re fine with breaking your API. Also, can you imagine using an API where half of the properties is exposed and the other one is hidden behind accessor methods?

I can’t think of a reasonable use case, with an exception of static public properties, which are, however, rarely used. Also, how often do you actually introduce a bug by assigning a value of an invalid type to your property?

Long story short, ditching accessor methods in favor of typed properties is most likely a bad idea.

There’s also another problem. PHP doesn’t profit from type-hints in any way; it’s just a runtime type check so it actually just makes your program slower. This doesn’t really stop me from using it, as I doubt it would make a measurable difference most of the time, but consider this:

class Generator
{
    private int $n;

    function run(): void
    {
        for (;;) {
            $this->n++;
            // ...
        }
    }
}

This is a no-no, once there’s a lot of iterations. Why? Because every time you assign a value to the $n, PHP will perform a type check. I believe there will be some optimizations made for such scenarios, but so far, this will slow execution down.

EDIT: In latest release, this exact code doesn’t seem to cause any performance degradation.

Did I mention this feature introduces an uninitialized state?

If a typed property does not have a default value, no implicit null default value is implied (even if the property is nullable). Instead, the property is considered to be uninitialized.

I sort of understand the reasoning behind it and I can definitely live with that, but I don’t like the behavior. Implicit null where possible and throwing an error when there’s an uninitialized property after the constructor call while maintaining the uninitialized property access check would make more sense, I guess.

Typed properties are a good thing in general, especially for static analysis and stuff like that. However, they’re not actually meant to reduce boilerplate. Accessor methods are still a thing you can’t avoid. In my opinion, the answer we’re looking for is something like properties in C#. That’s how you make a great API. I’ll stick with the Nette SmartObject, for now.