Що роблять суворі типи в PHP?


147

Я бачив наступний новий рядок у PHP 7, але ніхто насправді не пояснює, що це означає. Я переглянув це, і все, про що вони говорять, це ви будете це вмикати чи не подобатися у вигляді опитування.

declare(strict_types = 1);

Що це робить? Як це впливає на мій код? Чи варто це робити?

Деякі пояснення було б добре.



5
.Подивіться на це теж php.net/manual/en/… на директиву
строгих типів

Відповіді:


153

З блогу Treehouse :

З PHP 7 тепер ми додали скалярні типи. Зокрема: int, float, string та bool.

Додаючи підказки типу скалярного типу та уможливлюючи суворі вимоги, можна сподіватися, що можна написати більш правильні та самодокументовані програми PHP. Це також дає більше контролю над кодом і може полегшити його читання.

За замовчуванням скалярні декларації типу не суворі, це означає, що вони намагатимуться змінити початковий тип, щоб він відповідав типу, визначеному декларацією типу. Іншими словами, якщо ви передасте рядок, який починається з числа, у функцію, яка вимагає float, вона схопить число з самого початку і видалить усе інше. Передача поплавця у функцію, яка вимагає int, стане int (1).

За замовчуванням PHP передасть значення неправильного типу в очікуваний скалярний тип, якщо це можливо. Наприклад, функція, якій надано ціле число для параметра, який очікує, що рядок отримає змінну рядка типу.

Строгі типи вимкнено ( 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)
  */

Можна включити суворий режим на основі файлів. У суворому режимі буде прийнята лише змінна точного типу декларації типу, або викинеться TypeError. Єдиним винятком із цього правила є те, що функція, яка очікує поплавця, може бути задана цілим числом. Декларація строгих типів не впливатиме на виклики функцій з внутрішніх функцій.

Щоб увімкнути суворий режим, оператор заявлення використовується з декларацією строгого типу:

Включені строгі типи ( 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

Робочий приклад:

<?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');

3
Перша фатальна помилка, згадана у вашому прикладі суворих типів, є неправильною. Як зазначено в документації: "Єдиним винятком із цього правила є те, що функція, яка очікує плаву, може бути задана цілим числом". Виклик функції не відбувся б у int. Це було б на струні, хоча.
Пол,

63

strict_types впливає на примус типу.

Використання підказок типу без strict_typesможе призвести до тонких помилок.

До строгих типів int $xмалося на увазі " $xповинне мати значення, придатне до int". Будь-яке значення, яке може бути примушене до значення int, передає підказку типу, включаючи:

  • int власне ( 242),
  • поплавок ( 10.17),
  • bool ( true),
  • null, або
  • рядок з провідними цифрами ( "13 Ghosts").

Встановивши strict_types=1, ви скажете двигуну, що int $xозначає, що "$ x має бути лише правильним int, не допускається примушування типу". У вас є велика впевненість, що ви отримуєте саме та лише те, що було надано, без будь-якої конверсії та потенційних втрат.

Приклад:

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

Виходить потенційно заплутаний результат:

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

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

<?php declare(strict_types=1);

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

Врожайність:

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

Я думаю, тут є два уроки, якщо ви використовуєте підказки типу:

  • Використовуйте strict_types=1завжди.
  • Перетворіть повідомлення у винятки, якщо ви забудете додати strict_typesпрагму.

1
На це вже добре відповіли, як майже рік тому;)
emix

6
Дійсно, я відповів другою відповіддю @emix. Однак я відчув, що питання "чи повинен я це зробити" не торкнувся. Я також відчував, що більш компактний і шокуючий приклад спонукає людей до використання strict_types.
єпископ

1
Я думаю, що це питання лаконічно вирішує питання "Чи варто це робити?" частина питання ОП. Повернення до PHP після трохи перерви, і це було дуже корисно.
Darragh Enright
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.