PHP 8 переробив правила приведення рядків до чисел, зробивши їх суворішими й передбачуванішими.
Три види рядків:
- Числовий - лише число, з можливими пробілами на початку й у кінці:
'42',' 3.14 ','1e3'. - З числовим початком - число, а за ним інші символи:
'5 apples'. - Нечисловий - усе інше:
'abc',''.
В арифметиці:
'42' + 1; // 43
'5 apples' + 1; // 6 і Warning: A non-numeric value encountered
'abc' + 1; // TypeError
У PHP 7 'abc' + 1 давав 1 з попередженням - помилка тихо перетворювалася на нуль. Тепер це виняток.
У порівнянні ==:
- два числові рядки порівнюються як числа:
'1e3' == '1000'-true,'10' == '010'-true; - число з числовим рядком - як числа;
- число з нечисловим рядком - як рядки:
0 == 'abc'-falseу PHP 8 (у PHP 7 -true, бо'abc'ставав нулем).
Під declare(strict_types=1) скалярні параметри функцій не приводяться взагалі: int $id не прийме '5' - буде TypeError. Арифметичних операторів і порівнянь strict_types не стосується.
Практичні висновки:
- Дані з форм і запитів - завжди рядки. Приводьте їх явно й валідуйте (
(int),filter_var($v, FILTER_VALIDATE_INT), правила валідації Laravel), а не покладайтеся на неявне приведення. ===замість==, особливо для значень від користувача: «магічні хеші» на кшталт'0e123' == '0e456'(обидва - нуль у науковій нотації) досіtrue.- Для перевірки «чи це число» -
is_numeric()(приймає числові рядки) чиctype_digit()(лише цифри, без знаку й крапки).