Enabling 'Strict_Types' Globally in PHP 7

Enabling 'strict_types' globally in PHP 7

This is deliberately not possible, because the implementation adopted after an extremely long discussion of scalar type hints was this one: https://wiki.php.net/rfc/scalar_type_hints_v5

It introduces two modes for scalar type parameters, which both guarantee that the function receiving the parameters gets the types that it requires in its signature. However, it provides two modes for how calling code can achieve that:

  • in mode 0, it automatically validates and casts certain scalar types (e.g. int parameter will convert '123' to 123, but error on 'hello')
  • in mode 1, it requires the caller to do that validation and casting before-hand, and rejects any parameter not of the correct type (e.g. both '123' and 'hello' are rejected for an int parameter)

The choice of mode is per-file, and based on the caller of the function, because:

  • the setting needs to affect built-in functions as well as user-defined ones
  • all code that calls functions needs to be checked or updated to work correctly in mode 1, but most old code will run fine in mode 0
  • with a global setting, you could only use libraries which had been tested with both modes, or the same mode you prefer
  • files that don't declare their preferred mode need to continue to work similarly to PHP 5.x to allow existing code to run; that is only possible if the default is mode 0

From the point of view of someone writing a reusable library:

  • regardless of the setting, your functions are guaranteed to receive the parameter types requested
  • if you want to receive errors when you call functions with the wrong types, you can use mode 1 without forcing other applications and libraries to be on the same setting
  • if you want to have the automatic checks and casts of mode 0, you can do that, but still interact with other libraries and applications which run in mode 1
  • old libraries which were written before PHP 7.0 (or which needed to support both when it came out) will continue to work roughly as before, because the default mode 0 is similar to existing behaviour for built-in functions

It's therefore up to you to tell PHP which files have been written to use strict type mode, and which haven't; and the way to do this is using the declare statement.

Where to add 'strict_types' for PHP7 in Symfony?

It's a per-file directive, so you must put it in every file.

References:

  • http://php.net/manual/en/control-structures.declare.php

Strict mode in PHP

Kind of. You can activate the E_NOTICE level in your error reporting. (List of constants here.)

Every instance of usage of an undeclared variable will throw an E_NOTICE.

The E_STRICT error level will also throw those notices, as well as other hints on how to optimize your code.

error_reporting(E_STRICT);

Terminating the script

If you are really serious, and want your script to terminate instead of just outputting a notice when encountering an undeclared variable, you could build a custom error handler.

A working example that handles only E_NOTICEs with "Undefined variable" in them and passes everything else on to the default PHP error handler:

<?php

error_reporting(E_STRICT);

function terminate_missing_variables($errno, $errstr, $errfile, $errline)
{
if (($errno == E_NOTICE) and (strstr($errstr, "Undefined variable")))
die ("$errstr in $errfile line $errline");

return false; // Let the PHP error handler handle all the rest
}

$old_error_handler = set_error_handler("terminate_missing_variables");

echo $test; // Will throw custom error

xxxx(); // Will throw standard PHP error

?>

strict_types=1' does not seem to work in a function

"Strict types" mode only checks types at specific points in the code; it does not track everything that happens to the variable.

Specifically, it checks:

  • the parameters given to the function, if type hints are included in the signature; here you are giving two ints to a function expecting two ints, so there is no error
  • the return value of the function, if a return type hint is included in the signature; here you have no type hint, but if you had a hint of : int, there would still be no error, because the result of $a + $b + $c is indeed an int.

Here are some examples that do give errors:

declare(strict_types=1);
$a = '1';
$b = '2';
function FunctionName(int $a, int $b)
{
return $a + $b;
}
echo FunctionName($a, $b);
// TypeError: Argument 1 passed to FunctionName() must be of the type integer, string given

Or for a return hint:

declare(strict_types=1);
$a = 1;
$b = 2;
function FunctionName(int $a, int $b): int
{
return $a . ' and ' . $b;
}
echo FunctionName($a, $b);
// TypeError: Return value of FunctionName() must be of the type integer, string returned

Note that in the second example, it is not the fact that we calculated $a . ' and ' . $b that throws the error, it's the fact that we returned that string, but our promise was to return an integer. The following will not give an error:

declare(strict_types=1);
$a = 1;
$b = 2;
function FunctionName(int $a, int $b): int
{
return strlen( $a . ' and ' . $b );
}
echo FunctionName($a, $b);
// Outputs '7'

strict_types doesn't work when included

It is not currently possible to globally declare strict typing in PHP. From the manual:

It is possible to enable strict mode on a per-file basis

And

Strict typing applies to function calls made from within the file with strict typing enabled, not to the functions declared within that file. If a file without strict typing enabled makes a call to a function that was defined in a file with strict typing, the caller's preference (weak typing) will be respected, and the value will be coerced.

My guess is that, in part, this was to maintain compatibility amongst packages. What if you enable if globally and some package you're using requires strict typing to be off?

Until further notice you'll have to declare it in every file you're going to be using it.

PHP type hinting is being ignored, no TypeError exception is thrown

You need to add the strict_types directive for type hinting to work properly

Quoting from PHP 7 New Features

To enable strict mode, a single declare directive must be placed at the top of the file. This means that the strictness of typing for scalars is configured on a per-file basis. This directive not only affects the type declarations of parameters, but also a function's return type (see return type declarations, built-in PHP functions, and functions from loaded extensions.

With that, you should do this.

<?php
declare(strict_types=1);

function get_option_foo() : int {
$val = get_option('foo'); // Returns a string that can be parsed as an int
return (bool) $val;
}

$foo = get_option_foo();

Try this once again, you will receive an Uncaught TypeError Exception



Related Topics



Leave a reply



Submit