PHP Strict Typing

Why use strict typing in a language that supports dynamic types? It's all about managing the way PHP handles memory.

When I write PHP code, I typically start my project with a declare(strict_types = 1); directive. For long-time PHP fans this can come across as a bit odd. Why use strict typing in a language that supports dynamic types?

For me, it’s all three things: code readability, overall project maintainability, and performance.

The first two are somewhat debatable – readability and maintainability are somewhat subjective measures. But overall system performance it hard to disagree with. That said, it’s also not immediately apparent how typing actually contributes to system performance at all.

Code Forking

One of the more hand-wavey measures I point to is the way the application has to fork code to support dynamic types. If your function fails to declare types in its signature and is invoked with more than one variable type, PHP has to compile separate versions of the function to support the different types. This is done at compile time rather than runtime, so it’s not a huge issue.

But it does mean your application has to use twice as many bytes to represent a single piece of logic. When deploying to resource-constrained environments this limits your flexibility and makes your application feel more bloated on disk.

Memory Management

The more critical issue is how PHP handles variables in memory. Flexible types just take up more room to begin with! Consider the following two, trivial classes – functionally they’re identical and do nothing but hold 4 values in memory:

class FlexibleTypes
{
    public $first;
    public $second;
    public $third;
    public $fourth;

    public function __construct() {}

    public function setVars($first, $second, $third, $fourth)
    {
        $this->first = $first;
        $this->second = $second;
        $this->third = $third;
        $this->fourth = $fourth;
    }
}

class FixedTypes
{
    public int $first;
    public int $second;
    public int $third;
    public int $fourth;

    public function __construct() {}

    public function setVars(int $first, int $second, int $third, int $fourth)
    {
        $this->first = $first;
        $this->second = $second;
        $this->third = $third;
        $this->fourth = $fourth;
    }
}

The difference is that FlexibleTypes fails to declare the types of its properties while FixedTypes calls them out explicitly as integers. Run the following simple program to identify how much memory is consumed by each:

function get_memory()
{
    global $base_memory;

    echo memory_get_usage() - $base_memory . PHP_EOL;
}

$base_memory = memory_get_usage();

get_memory();

$flex = new FlexibleTypes();

get_memory();

$flex->setVars(1, 2, 3, 4);

get_memory();

echo '----' . PHP_EOL;

$fixed = new FixedTypes();

get_memory();

$fixed->setVars(1, 2, 3, 4);

get_memory();

When setting all four properties, FlexibleTypes consumes 144 bytes of memory. Doing the exact same thing with identical values, FixedTypes only consumes 112 bytes. Merely declaring our types has saved us considerable space in memory.

Use Strict Typing

This example is remarkably trivial but points out a very critical issue – PHP must allocate more memory to house data in a dynamically-typed variable than it does for a strictly-typed one. As your applications become more complex you’ll be handling far more data than four small integers. The impact of strict typing on your application’s memory usage will be significantly greater!

Even in a dynamic language like PHP, you owe it to yourself to learn how to handle types properly.

#