281

I've seen the following new line in PHP 7, but nobody really explains what it means. I've googled it and all they talk about is will you be enabling it or not like a poll type of thing.

declare(strict_types = 1);

What does it do? How does it affect my code? Should I do it?

Some explanation would be nice.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sufuko
  • 2,829
  • 2
  • 8
  • 3

3 Answers3

269

From the Treehouse blog:

With PHP 7 we now have added Scalar types. Specifically: int, float, string, and bool.

By adding scalar type hints and enabling strict requirements, it is hoped that more correct and self-documenting PHP programs can be written. It also gives you more control over your code and can make the code easier to read.

By default, scalar type-declarations are non-strict, which means they will attempt to change the original type to match the type specified by the type-declaration. In other words, if you pass a string that starts with a number into a function that requires a float, it will grab the number from the beginning and remove everything else. Passing a float into a function that requires an int will become int(1).

By default, PHP will cast values of the wrong type into the expected scalar type if possible. For example, a function that is given an integer for a parameter that expects a string will get a variable of type string.

Strict types disabled (eval):

<?php

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

  echo AddIntAndFloat(1.4, '2');
  /*
  * without strict typing, PHP will change float(1.4) to int(1)
  * and string('2') to float(2.0) and returns int(3)
  */

It is possible to enable strict mode on a per-file basis. In strict mode, only a variable of exact type of the type declaration will be accepted, or a TypeError will be thrown. The only exception to this rule is that an integer may be given to a function expecting a float. Function calls from within internal functions will not be affected by the strict_types declaration.

To enable strict mode, the declare statement is used with the strict_types declaration:

Strict types enabled (eval):

<?php declare(strict_types=1);

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

  echo AddIntAndFloat(1.4,'2');
  // Fatal error: Uncaught TypeError: Argument 1 passed to AddIntAndFloat() must be of the type int, float given
  echo AddIntAndFloat(1,'2');
  // Fatal error: Uncaught TypeError: Argument 2 passed to AddIntAndFloat() must be of the type float, string given

  // Integers can be passed as float-points :
  echo AddIntAndFloat(1,1);
  // Fatal error: Uncaught TypeError: Return value of AddIntAndFloat() must be of the type integer, string returned

Working example:

<?php

declare(strict_types=1);

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

$float = AddFloats(1.5,2.0); // Returns 3.5

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

$int = AddFloatsReturnInt($float,1.5); // Returns 5

function Say(string $message): void // As in PHP 7.2
{
    echo $message;
}

Say('Hello, World!'); // Prints "Hello, World!"

function ArrayToStdClass(array $array): stdClass
{
    return (object) $array;
}

$object = ArrayToStdClass(['name' => 'azjezz','age' => 100]); // returns an stdClass

function StdClassToArray(stdClass $object): array
{
    return (array) $object;
}

$array = StdClassToArray($object); // Returns array

function ArrayToObject(array $array): object // As of PHP 7.2
{
    return new ArrayObject($array);
}

function ObjectToArray(ArrayObject $object): array
{
    return $object->getArrayCopy();
}

var_dump( ObjectToArray( ArrayToObject( [1 => 'a' ] ) ) ); // array(1 => 'a');
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
azjezz
  • 3,827
  • 1
  • 14
  • 35
111

strict_types affects type coercion.

Using type hints without strict_types may lead to subtle bugs.

Prior to strict types, int $x meant "$x must have a value coercible to an int." Any value that could be coerced to an int would pass the type hint, including:

  • an int proper (242),
  • a float (10.17),
  • a bool (true),
  • null, or
  • a string with leading digits ("13 Ghosts").

By setting strict_types=1, you tell the engine that int $x means "$x must only be an int proper, no type coercion allowed." You have great assurance you're getting exactly and only what was given, without any conversion and potential loss.

Example:

<?php
function get_quantity(): int {
    return '100 apples';
}
echo get_quantity() . PHP_EOL;

Yields a potentially confusing result:

Notice: A non well formed numeric value encountered in /Users/bishop/tmp/pmkr-994/junk.php on line 4
100

Most developers would expect, I think, an int hint to mean "only an int". But it doesn't, it means "anything like an int". Enabling strict_types gives the likely expected and desired behavior:

<?php declare(strict_types=1);

function get_quantity(): int {
    return '100 apples';
}
echo get_quantity() . PHP_EOL;

Yields:

Fatal error: Uncaught TypeError: Return value of get_quantity() must be of the type int, string returned in example.php:4

I think there's two lessons here, if you use type hints:

  • Use strict_types=1, always.
  • Convert notices to exceptions, in case you forget to add the strict_types pragma.
bishop
  • 37,830
  • 11
  • 104
  • 139
  • 1
    This answer is good because it highlights scenarios with other types, but is also a tad misleading. Some notes: 1. NULL will never cast properly, strict mode or not. It always throws a fatal error. 2. Not to diminish the usefulness of strict mode, notices (from bad string casts) can be caught and converted to an exception - and often are by most frameworks. – gwillz Oct 25 '22 at 23:02
3

Short answer

Type hinting in method parameters or class properties is very useful and it helps you catch type errors before you run your code. Class based type hinting has worked since PHP 5, but primitive hinting is rather new. When passing an unexpected type to a function, PHP will attempt to automatically cast the value to the expected type. If strict_types has been declared then PHP will throw an exception instead.

Long answer

Using declare(strict_types=1) will tell PHP to throw type errors when you try to (accidentally) cast primitive values. Take a look at this example without the strict type declaration.

function dump(int $value): void  
{  
 var_dump($value);  
}  

dump('13.37');
dump(19.42);

Running this script will result in the following output:

int(13)
int(19)

You'll notice that our dump function expects integers even though we give it a string in one of our function calls. Your editor might call you out if you try to do this, but it's still valid PHP code.

Enabling strict typing for primitive values is as easy as adding a single statement to the top of your PHP files. Here is the example from above with the added declaration.

declare(strict_types=1)

function dump(int $value): void  
{  
 var_dump($value);  
}  

dump('13.37');
dump(19.42);

Running this script with the declaration will result in the following error:

Fatal error: Uncaught TypeError: dump(): Argument #1 ($value) must be of type int, string given, called in /Users/rienvanvelzen/Desktop/demo.php on line 10 and defined in /Users/rienvanvelzen/Desktop/demo.php:5
Stack trace:
#0 /Users/rienvanvelzen/Desktop/demo.php(10): dump('13.37')
#1 {main}
  thrown in /Users/rienvanvelzen/Desktop/demo.php on line 5

Using the strict_type declaration can help you catch bugs early on by restricting PHP to automatically cast primitive values. It may be a bit daunting when you start to use it, as you need to properly define everything from the start.

Source: The way declare(strict_types=1) works in PHP

MiraTech
  • 1,108
  • 18
  • 35