Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does PHP strict typing allow function arguments of wrong type?

Tags:

types

php

php-7.4

I'm using PHP 7.4.16. I enabled strict_types in my PHP file thinking it would prevent passing a string argument to a function expecting an int by throwing a TypeError. However, the function actually accepts the string and coerces it to an int. But if I place a return type hint on the function it works as expected, throwing a TypeError.

This doesn't make sense to me and seems like a glaring inconsistency that can lead to bugs. Does anyone have any insight as to why this is or if I'm doing something wrong?

Test code:

<?php
declare(strict_types=1);

$ids = ['1', '2', '3'];

// No error thrown, coerces string argument to int.
array_map(fn (int $id) => $id, $ids);

// Throws PHP Fatal error:  Uncaught TypeError: Return value of {closure}() must be of the type int, string returned
array_map(fn ($id): int => $id, $ids);
like image 390
Jacob Avatar asked Sep 13 '25 14:09

Jacob


1 Answers

strict_types only affects function calls within the file in which it's declared. From the PHP docs:

Note: 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 (coercive typing) will be respected, and the value will be coerced.

In your case, the examples are not calling the callback itself, they are passing it as an argument for array_map, meaning that wherever the function array_map is implemented, it has preference for coercive typing when array_map is calling your callback.

A possible solution to this would be to wrap array_map and make the call to your callback in a file in which strict_types is declared, such as this:

<?php
declare(strict_types=1);

$ids = ['1', '2', '3'];

function strict_array_map($fn, $arr){
    return array_map(fn (...$arguments) => $fn(...$arguments), $arr);
}

// Now TypeError is thrown correctly
strict_array_map(fn (int $id) => $id, $ids);

// Throws PHP Fatal error:  Uncaught TypeError: Return value of {closure}() must be of the type int, string returned
strict_array_map(fn ($id): int => $id, $ids);

https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict

like image 81
Alex Ruiz Avatar answered Sep 16 '25 05:09

Alex Ruiz