Why Class Constants Should be Typed

Do you use PHP 7.4 typed properties? Do you know why?

I use them, so I don't have to think and validate the property type every time. We just know its type or PHP would crash otherwise.

Until PHP 7.4 this was not possible and code was kinda crappy. Where are we now with constant type? Do you trust your class constants type?

With typed properties, the incorrect type-bug was completely removed:

<?php

declare(strict_types=1);

final class Person
{
    public string $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }
}
$name = new Person(20_20);

You would not use the Name object like this, right?


What About Constants?

What are constants? They hold value, like properties, but the value doesn't change. We can change the value in the code, but not during runtime.

Pro-tip: Do you think all your properties have values that can change? Dare Rector to find them.

How do you define a class constant?

<?php

final class SomeClass
{
    private const ORDER = 'first';

    // ...
}

How is this dangerous? Sometimes, in 2 years future from today, there will be pull-request that changes it like this:

<?php

final class SomeClass
{
    private const ORDER = 1;
}

Because if you're first, you're 1, right? I had the pleasure to debug such cases only to figure out the constant type was changed. Why? Because it could.

Constants value can be changed manually - so their type. It's rarely desired behavior, moreover, when using these constants in 3rd party code or from one.

How Can We Prevent Constant Re-type?

<?php

final class SomeClass
{
    /**
     * Should be a string
     */
    private const ORDER = 'first';
}

We read comments, READMEs, or manuals... only when something goes wrong.

<?php

final class SomeClass
{
    /**
     * @var string
     */
    private const ORDER = 'first';
}

Slightly better, but still no way to enforce it.

<?php

final class SomeClass
{
    private string const ORDER = 'first';
}

Great! But maybe in 2025?

Future Scoping

The PHP 8.0 release will be a blast. It's already ~30 merged features, and feature freeze is still 23 days ahead of us.

If we look at selected features in PHP 8:

We can see there is a handful of changes towards more strict and reliable types. We are moving from docblocks to in-code types.

We can expect similar future for constants. Maybe even sooner before TypedArrays[] will be added.

In 2015, we wished for typed properties, and in 2020 we have union strictly typed properties. We can go for typed constants now.

Check trends to predict code syntax,
and write future compatible code your children will thank you for.

Let Computer work For You

The sooner you discover the error, the better.

Do you use continuous integration (Github Actions, Gitlab CI, Travis CI...) and PHPStan? Add PHPStan rule that checks @var definition vs the real value.

 <?php

 final class SomeClass
 {
     /**
      * @var string
      */
-    private const ORDER = 'first';
+    private const ORDER = 1;
 }

If this change occurs in pull-request, the CI will tell you it's not consistent with the @var type.

This way, you'll be aware of the type change right before the merge, which is much better than 2 years later after 4 hours of debugging. Trust me.


Happy coding!




Do you learn from my contents or use open-souce packages like Rector every day?
Consider supporting it on GitHub Sponsors. I'd really appreciate it!