• Reading time ~ 6 min
  • 24.05.2023

Introduction

If you're a PHP developer, you've probably seen the statement declare(strict_types=1) at the beginning of some PHP files.

The first time I saw this statement, I had no idea what it did. I assumed it was some kind of comment or maybe sort of old PHP syntax that was before my time, but I was wrong (very wrong!).

In this Quickfire article, we'll cover what declare(strict_types=1) is and how it can help you improve the type safety of your PHP code.

What is declare(strict_types=1)?

declare(strict_types=1) is a statement that enforces strict typing in PHP applications.

When you use this statement, PHP will perform strict type-checking on function parameters and return types. This means that if a function is expecting a certain type of parameter or return value, PHP will throw an error if the wrong type is used.

Let's take a simple example that doesn't use declare(strict_types=1):

function add(int $a, int $b): int
{
    return $a + $b;
}

Now let's say we called this function with string parameters:

echo add('1', '2');
 
// Output:
// 3

PHP will happily convert the string parameters to integers and return the result 3.

In some cases, you may be completely fine with this behaviour. But it could have some unintended consequences that you didn't expect and that could cause bugs in your application.

However, let's imagine that we wanted to use declare(strict_types=1) in this example. We could do this by adding the following statement at the top of the file:

declare(strict_types=1);
 
function add(int $a, int $b): int
{
    return $a + $b;
}

Now, if we call the add function with string parameters, PHP will throw an error:

echo add('1', '2');
 
// Output:
// Fatal error: Uncaught TypeError: Argument 1 passed to add() must be of the type int, string given
As we can see here, PHP has thrown an error because the add function expected integers to be passed, but received strings instead.

Similarly, PHP will also throw errors if strict type-checking is enabled and we try to return the wrong data type from the method. For example, let's say our add function now accepts floats instead of integers and that we don't have strict type-checking enabled:

function add(float $a, float $b): int
{
    return $a + $b;
}

We could then call the function like so:

echo add(1.25, 2.25);
 
// Output:
// 3
Did you spot the problem in the output?

The answer we should have received is 3.5. However, because we have defined the return type as int, we've converted the float (that was supposed to be returned) to an integer and lost the precision. As you can imagine, this could cause some issues in other parts of our application where we're using this result and the precision may have been needed.

Now let's fix this issue by using declare(strict_types=1):

declare(strict_types=1);
 
function add(float $a, float $b): int
{
    return $a + $b;
}
We could then call the function like so:
echo add(1.25, 2.25);
 
// Output:
// Fatal error: Uncaught TypeError: add(): Return value must be of type int, float returned

As we can see, by enabling strict type-checking, we can spot that the function isn't returning the correct data type. This is great because it could be highlighting a possible bug in our code that we didn't know about. We could then take the necessary steps to either:

  • Update the return types if they are incorrect
  • Update the type hints if they are incorrect
  • Update the function body to return the correct data type if it's incorrect
  • Fix any bugs in the code calling the function that may be passing the incorrect data type to it

Should I Use declare(strict_types=1)?

Personally, I think it's a good idea to use declare(strict_types=1) in all of your PHP files. I used to think that just having type hints and return types was enough to ensure that the correct data types were being passed, but I've since changed my mind. I feel much more confident in my code when I use declare(strict_types=1) and have found a few bugs as a result of using it (in particular when adding it to older code bases).

Since learning about it, I make it a habit to use it in every new PHP file that I create. In fact, I updated all the templates in my PhpStorm set up so that it's automatically included at the top of every file I create. For example, here's the template that's used when creating a new PHP class:

 <?php
 
 declare(strict_types=1);
 
 #parse("PHP File Header.php")
 
 #if (${NAMESPACE})
 namespace ${NAMESPACE};

 #end
class ${NAME} {

}

This is really handy because it encourages me to keep using declare(strict_types=1) without me needing to make any manual changes after creating the file (which I would definitely forget to do!).

For any of my Laravel readers, you can also publish the stubs that are used for creating PHP files when running Artisan commands such as php artisan make:controller. By publishing the stubs, you can edit them and add declare(strict_types=1) to the top. This means that the files you create using the Artisan commands will be created with stricter type safety already enabled.

Of course, if you are going to add stricter type-checking to your existing files, I would strongly advise having a good-quality test suite in place first. Your PHP code may have been allowing the incorrect data types to be passed without throwing any errors. But, by enabling strict type-checking, your code will become much less forgiving and may start throwing errors. This could cause your application to break in unexpected ways for your users.

You may also find that you need to refactor some of your code to make it compatible with declare(strict_types=1). I wouldn't see this as a bad thing though. Instead, I would see it as an opportunity to improve the quality of your code.

To help with the process of adding declare(strict_types=1) to your code, you may want to use a tool like PHPStan that may pick up on these type mismatches for you.

Conclusion

Hopefully, this article has given you a quick overview of what declare(strict_types=1) is and how it can help you improve the type safety of your PHP code.

If you enjoyed reading this post, I'd love to hear about it. Likewise, if you have any feedback to improve the future ones, I'd also love to hear that too.

You might also be interested in checking out my 220+ page ebook "Battle Ready Laravel" which covers similar topics in more depth.

If you're interested in getting updated each time I publish a new post, feel free to sign up for my newsletter below.

Keep on building awesome stuff! 🚀

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

ABOUT

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

About author CrazyBoy49z
WORK EXPERIENCE
Contact
Ukraine, Lutsk
+380979856297