PHP Strict Types

In December 2015, PHP 7 introduced scalar type declarations and with it the strict_types flag. This flag can be used to enforce the type of value passed to functions. Although I have seen it in action in the past, I have never actually used it before so I decided to look into it a little to see what it was about.

For some background, types are not strictly enforced in PHP. This means that it is not only possible to swap the type of a variable from one type to another, but it is also possible to swap a variable of one type to another depending on the context being used. Programmers getting started in PHP will spot this when attempting to print out a boolean value as this will be cast to an integer before being printed out. This means that when attempting to print 'true' PHP will instead print out '1'. PHP will automatically coerces values to be one type to another when passing values to functions.

With scalar type declarations enabled, the values passed to a function must be the types that the function is stated to receive. By default, scalar type declarations are off in PHP. They must be enabled by adding the strict_types=1 declaration at the top of each file.

The declaration looks like this. It must be placed before any other code in the file and will only effect the file is has been placed in.

<?php

declare(strict_types=1);

Let's look at this in action by taking the following function. This function accepts an integer value and will print out the value as a var dump.

<?php

function doThing(int $int) {
  var_dump($int);
}

Thanks to the loosely typed nature of PHP we can pass a number of different values to this function, each of which will be automatically cast to an integer value. For every value here the value printed is an integer of 1, even though the original value passed was not, in all cases, an integer

doThing(1); // prints int(1)
doThing("1"); // prints int(1)
doThing(TRUE); // prints int(1)
doThing(1.0); // prints int(1)

Now, if we add the strict_types declaration to the top of the file we can attempt to run the same code again.

<?php

declare(strict_types=1);

function doThing(int $int) {
  var_dump($int);
}

doThing(1);
doThing("1");
doThing(TRUE);
doThing(1.0);

The first line (sending an integer value) works just fine as the function requires an integer value to be passed to it. As soon as we try to pass any other type of value to the function we see the following error being produced. As the second call to the function is actually a string the following error is produced.

PHP Fatal error:  Uncaught TypeError: Argument 1 passed to doThing() must be of the type
int, string given, called in test.php on line 10 and defined in test.php:5

The scalar type declaration prevents you from sending variables of a different type to a function. Normally, PHP will cast them to the correct value, but with scalar types declaration enabled it will instead throw a fatal error.

We can also enforce the return types of functions with scalar type declarations. The following code defines a function that will accept an integer value and should return an integer value. There is a deliberate error in the code though as it will only return a float value.

<?php

declare(strict_types = 1);

function doThing(int $int) : int {
  return 1.0;
}

doThing(1);

Running the above code will produce a type error like this.

PHP Fatal error:  Uncaught TypeError: Return value of doThing() must be of the type int,
float returned in test.php:7

Note that I mentioned previously that the scalar type declaration must be placed at the top of every file. This means that if the function is defined in one file with scalar type declaration enabled and called from another then the scalar type declaration setting isn't applied.

Let's take an example and put the function we defined before in a file with the scalar type declaration set.

<?php

declare(strict_types=1);

function doThing(int $int) {
  var_dump($int);
}

Now, in a second file we include the first file and then attempt to call the function using a value that is not an integer.

<?php

require_once('functions.php');

doThing("1");

Running the code in this way does not produce any errors. This is because the file that initiates the call to the function does not contain the scalar type declaration. Only if the second file contains the declaration does the code error.

Fundamentally, the scalar type declaration is more for the reader of the code, rather than the programmer using the code. The fact that it must be added to the top of all files enforces it on a file-by-file basis and so if it is added to a third party library it won't matter to the code using that library.

Having looked into this feature of PHP I think I will start using it in my code to enforce types passed to and from functions. Also, due to the fact that it only works in the file it is defined in the effect on any upstream code is minimal and so it won't cause any unwanted problems.

If you are interested, you can see the original RFC for scalar type hints on the PHP wiki.

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
8 + 1 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.