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 enables PHP's strict mode and enforces strict typing in your PHP applications.
It was added back in PHP 7.0, when the type declaration system was first implemented in PHP. This means it's available to use in your PHP 8 projects so you can start making the most of strict types in your code.
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. This also applies to PHP closures and arrow functions that have type hints and return types specified.
Let's take a simple example that doesn't use declare(strict_types=1)
:
1function add(int $a, int $b): int2{3 return $a + $b;4}
Now let's say we called this function with string parameters:
1echo add('1', '2');2 3// Output:4// 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:
1declare(strict_types=1);2 3function add(int $a, int $b): int4{5 return $a + $b;6}
Now, if we call the add
function with string parameters, PHP will throw an error:
1echo add('1', '2');2 3// Output:4// 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:
1function add(float $a, float $b): int2{3 return $a + $b;4}
We could then call the function like so:
1echo add(1.25, 2.25);2 3// Output:4// 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)
:
1declare(strict_types=1);2 3function add(float $a, float $b): int4{5 return $a + $b;6}
We could then call the function like so:
1echo add(1.25, 2.25);2 3// Output:4// 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 that matches the return type declaration. 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).
Due to PHP being a dynamically typed language (and not a strict typed language), it means you don't need to specify any return types or type hints at all if you don't want. Instead, PHP will determine the types at runtime for you. However, even though it's possible to do this, I'd strongly recommend against doing it. If you aren't able to use the strict types in your code (for whatever reason), I'd still recommend using type hints and return types as a bare minimum to improve your PHP code quality.
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:
1<?php 2 3declare(strict_types=1); 4 5#parse("PHP File Header.php") 6 7#if (${NAMESPACE}) 8namespace ${NAMESPACE}; 910#end11class ${NAME} {1213}
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.
As a side note, if you're interested in implementing a good-quality test suite for your Laravel applications, you might be interested in checking out my book Battle Ready Laravel. There is a dedicated section that teaches you techniques that you can use for writing tests for mission-critical parts of your code, running your tests in CI using GitHub Actions, how to write UI tests using Laravel Dusk, and much more.
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! 🚀