Type Juggling

Оновлено: 12.05.2023

PHP не вимагає явного визначення типу при оголошенні змінної. У цьому випадку тип змінної визначається значенням, яке вона зберігає. Тобто, якщо змінній $var присвоюється рядок, то $var має тип string. Якщо після цього змінній $var присвоюється значення типу int, то вона буде мати тип int.

У певних контекстах PHP може намагатися автоматично перетворити тип значення в інший. Існують різні контексти:

Числовий Рядок Логічний Інтеграл та рядок Порівняльна Функція

Примітка: Коли значення потрібно інтерпретувати як інший тип, саме значення не змінює тип.

Щоб змусити змінну обчислюватися як певний тип, див. розділ про приведення типів. Щоб змінити тип змінної, скористайтеся функцією settype().

Це контекст при використанні арифметичного оператора.

У цьому контексті, якщо один з операндів є числом з плаваючою комою (або не може бути інтерпретований як int), обидва операнди інтерпретуються як числа з плаваючою комою, і результатом буде число з плаваючою комою. В іншому випадку операнди буде інтерпретовано як int, і результатом також буде int. Починаючи з версії PHP 8.0.0, якщо один з операндів не може бути інтерпретований, генерується помилка типу TypeError.

Це контекст при використанні ехо, друку, інтерполяції рядків або оператора конкатенації рядків.

У цьому контексті значення буде інтерпретовано як рядок. Якщо значення не може бути інтерпретовано, буде згенеровано помилку типу TypeError. До версії PHP 7.4.0 генерувалася помилка E_RECOVERABLE_ERROR.

Це контекст при використанні умовних операторів, тернарного оператора або логічного оператора.

У цьому контексті значення буде інтерпретовано як bool.

Це контекст при використанні побітових операторів.

У цьому контексті, якщо всі операнди мають тип string, результат також буде рядком. В іншому випадку операнди будуть інтерпретовані як int, і результатом також буде int. Починаючи з версії PHP 8.0.0, якщо один з операндів не може бути інтерпретований, буде згенеровано помилку типу TypeError.

Це контекст при використанні оператора порівняння.

Перетворення типів, які відбуваються в цьому контексті, пояснюються в таблиці Порівняння з різними типами.

Це контекст, коли значення передається типізованому параметру, властивості або повертається з функції, яка оголошує тип повернення.

У цьому контексті значення повинно бути значенням типу. Існує два винятки: якщо значення має тип int, а оголошений тип float, то ціле число перетворюється на число з плаваючою комою. Другий виняток: якщо оголошений тип є скалярним, значення перетворюється до скалярного типу, а режим примусової типізації активний (за замовчуванням), значення може бути перетворено до прийнятного скалярного значення. Опис такої поведінки наведено нижче.

Внутрішні функції автоматично приводять нульові типи до скалярних, ця поведінка застаріла, починаючи з PHP 8.1.0.

оголошення типу bool: значення інтерпретується як bool. оголошення типу int: значення інтерпретується як int, якщо перетворення добре визначене. Тобто рядок є числовим. оголошення типу float: значення інтерпретується як float, якщо перетворення визначено. Тобто рядок є числовим. оголошення типу string: значення інтерпретується як рядок.

Коли строгі_типи не увімкнено, оголошення скалярних типів підлягають обмеженому неявному примусу до типу. Якщо точний тип значення не є частиною об'єднання, то цільовий тип вибирається у наступному порядку:

int float рядок bool

Як виняток, якщо значення є рядком і в об'єднанні є як int, так і float, переважний тип визначається існуючою семантикою числового рядка. Наприклад, для "42" буде обрано тип int, а для "42.0" - тип float.

Зауважте:

Типи, які не входять до наведеного вище списку преференцій, не є прийнятними цілями для неявного примусу. Зокрема, не відбувається неявного примусу до типів null, false та true.

Приклад #1 Приклад примусового включення типів до типової частини об'єднання

<?php
// int|string
42    --> 42          // exact type
"42"  --> "42"        // exact type
new ObjectWithToString --> "Result of __toString()"
                      // object never compatible with int, fall back to string
42.0  --> 42          // float compatible with int
42.1  --> 42          // float compatible with int
1e100 --> "1.0E+100"  // float too large for int type, fall back to string
INF   --> "INF"       // float too large for int type, fall back to string
true  --> 1           // bool compatible with int
[]    --> TypeError   // array not compatible with int or string

// int|float|bool
"45"    --> 45        // int numeric string
"45.0"  --> 45.0      // float numeric string

"45X"   --> true      // not numeric string, fall back to bool
""      --> false     // not numeric string, fall back to bool
"X"     --> true      // not numeric string, fall back to bool
[]      --> TypeError // array not compatible with int, float or bool
?>

Приведення типу перетворює значення до вибраного типу, записуючи тип у дужках перед значенням, яке потрібно перетворити.

<?php
$foo = 10;   // $foo is an integer
$bar = (bool) $foo;   // $bar is a boolean
?>

Допускаються такі акторські роботи:

(int) - приведення до типу int (bool) - приведення до bool (float) - приведення до типу float (string) - приведення до рядка (array) - приведення до масиву (object) - приведення до об'єкта (unset) - приведення до NULL

Зауважте:

(integer) є псевдонімом приведення (int). (boolean) - псевдонім приведення (bool). (binary) є псевдонімом типу (string). (double) і (real) є псевдонімами типу (float). Ці приведення не використовують канонічну назву типу і не рекомендуються.

(Справжній) кастований псевдонім застаріло починаючи з версії PHP 8.0.0.

Приведення (unset) застаріло починаючи з версії PHP 7.2.0. Зауважте, що приведення (unset) - це те саме, що присвоєння значення NULL змінній або виклику. Приведення (unset) вилучено починаючи з версії PHP 8.0.0.

Приведення (бінарний) і префікс b існують для підтримки прямого виводу. Наразі (бінарний) і (рядок) ідентичні, проте це може змінитися, і на це не слід покладатися.

Зауважте:

Пробіли ігноруються у дужках приведення. Таким чином, наступні два приведення є еквівалентними:

<?php
$foo = (int) $bar;
$foo = ( int ) $bar;
?>

Приведення буквених рядків і змінних до двійкових рядків:

<?php
$binary = (binary) $string;
$binary = b"binary string";
?>

Зауваження: Замість приведення змінної до рядка можна також взяти змінну в подвійні лапки.

<?php
$foo = 10;            // $foo is an integer
$str = "$foo";        // $str is a string
$fst = (string) $foo; // $fst is also a string

// This prints out that "they are the same"
if ($fst === $str) {
    echo "they are the same";
}
?>

Може бути неочевидно, що саме станеться при кастингу між певними типами. Для отримання додаткової інформації див. ці розділи:

  • Перетворення в булевий тип
  • Перетворення в ціле число
  • Перетворення в число з плаваючою комою
  • Перетворення в рядок
  • Перетворення в масив
  • Перетворення в об'єкт
  • Перетворення в ресурс
  • Приведення до NULL
  • Таблиці порівняння типів

Зауваження: Оскільки PHP підтримує індексування рядків за допомогою зсувів, використовуючи той самий синтаксис, що й індексування масивів, наступний приклад є правильним для всіх версій PHP:

<?php
$a    = 'car'; // $a is a string
$a[0] = 'b';   // $a is still a string
echo $a;       // bar
?>