Do czego służą typy ścisłe w PHP?

160

Widziałem następującą nową linię w PHP 7, ale nikt tak naprawdę nie wyjaśnia, co to znaczy. Przeszukałem go w Google i mówią tylko o tym, czy włączysz to, czy nie, jak w ankiecie.

declare(strict_types = 1);

Co to robi? Jak to wpływa na mój kod? Czy powinienem to zrobić?

Jakieś wyjaśnienie byłoby miłe.

sufuko
źródło
1
php.net/declare
JBES,
5
. spójrz na to też php.net/manual/en/ ... dla dyrektywy
strict_types

Odpowiedzi:

163

Z bloga Treehouse :

W PHP 7 dodaliśmy teraz typy skalarne. W szczególności: int, float, string i bool.

Istnieje nadzieja, że ​​dodając wskazówki dotyczące typów skalarnych i umożliwiając rygorystyczne wymagania, można napisać bardziej poprawne i samodokumentujące się programy PHP. Zapewnia również większą kontrolę nad kodem i może ułatwić jego odczytywanie.

Domyślnie deklaracje typu skalarnego nie są ścisłe, co oznacza, że ​​będą próbować zmienić typ oryginalny, aby pasował do typu określonego w deklaracji typu. Innymi słowy, jeśli przekażesz ciąg zaczynający się od liczby do funkcji wymagającej liczby zmiennoprzecinkowej, przejmie ona liczbę od początku i usunie wszystko inne. Przekazanie liczby zmiennoprzecinkowej do funkcji, która wymaga wartości int, stanie się int (1).

Domyślnie PHP będzie rzutować wartości niewłaściwego typu na oczekiwany typ skalarny, jeśli to możliwe. Na przykład funkcja, której podano liczbę całkowitą dla parametru, który oczekuje ciągu, otrzyma zmienną typu ciąg.

Ścisłe typy wyłączone ( 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)
  */

Możliwe jest włączenie trybu ścisłego dla każdego pliku. W trybie ścisłym akceptowana będzie tylko zmienna o dokładnym typie deklaracji typu lub zostanie wyrzucony błąd TypeError. Jedynym wyjątkiem od tej reguły jest to, że funkcja oczekująca na wartość zmiennoprzecinkową może otrzymać liczbę całkowitą. Na wywołania funkcji z funkcji wewnętrznych nie będzie miała wpływu deklaracja strict_types.

Aby włączyć tryb ścisły, deklaracja deklaracji jest używana z deklaracją strict_types:

Włączono ścisłe typy ( 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

Przykład pracy:

<?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');
saif
źródło
3
Pierwszy błąd krytyczny wymieniony w przykładzie włączonych typów ścisłych jest nieprawidłowy. Jak wspomniano w dokumentacji: „Jedynym wyjątkiem od tej reguły jest to, że funkcja oczekująca na wartość zmiennoprzecinkową może otrzymać liczbę całkowitą”. Wywołanie funkcji nie zawiedzie w int. Byłoby to na sznurku.
Paul
66

strict_types wpływa na wymuszenie typu.

Używanie podpowiedzi typu bez podpowiedzi strict_typesmoże prowadzić do subtelnych błędów.

Przed typami ścisłymi int $xoznaczało „ $xmusi mieć wartość podlegającą przekształceniu na int”. Każda wartość, która mogłaby zostać wymuszona na an int, przekazałaby wskazówkę dotyczącą typu, w tym:

  • int właściwy ( 242),
  • pływak ( 10.17),
  • a bool ( true),
  • nulllub
  • ciąg z początkowymi cyframi ( "13 Ghosts").

Ustawiając strict_types=1, mówisz silnikowi, że int $xoznacza to, że „$ x musi być tylko int właściwym, nie jest dozwolone żadne wymuszanie typu”. Masz wielką pewność, że otrzymujesz dokładnie i tylko to, co zostało dane, bez jakiejkolwiek konwersji i potencjalnej straty.

Przykład:

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

Daje potencjalnie mylący wynik:

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

Większość programistów spodziewałaby się, jak sądzę, intwskazówki oznaczającej „tylko int”. Ale tak nie jest, to znaczy „coś w rodzaju int”. Włączenie strict_types daje prawdopodobne oczekiwane i pożądane zachowanie:

<?php declare(strict_types=1);

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

Plony:

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

Myślę, że są tu dwie lekcje, jeśli używasz wskazówek dotyczących pisania:

  • Używaj strict_types=1zawsze.
  • Przekształć powiadomienia w wyjątki, na wypadek gdybyś zapomniał dodać strict_typespragmę.
biskup
źródło
1
Odpowiedź na to pytanie została już dobrze odebrana, jak prawie rok temu;)
emix
7
Rzeczywiście, głosowałem za drugą odpowiedzią @emix. Jednak czułem, że pytanie „czy powinienem to zrobić” nie zostało poruszone. Czułem też, że bardziej zwarty i szokujący przykład zachęciłby ludzi do używania strict_types.
biskup
2
Myślę, że to pytanie zwięźle odpowiada na pytanie „Czy powinienem to zrobić?” część pytania PO. Powrót do PHP po krótkiej przerwie i to było bardzo pomocne.
Darragh Enright
2

Ścisłe typy w PHP mają wpływ na typy przymusu.

Ustawiając „strict_types = 1”, mówisz silnikowi, że „int $ x” oznacza, że ​​„$ x musi być tylko wartością typu int, a wymuszenie typu nie jest dozwolone”. Masz wielką pewność, że otrzymujesz dokładnie i tylko to, co zostało dane, bez jakiejkolwiek konwersji lub potencjalnej straty.

Wszystko, co musisz wiedzieć o typach ścisłych w PHP :)

https://medium.com/@chemaclass/strict-types-in-php-d4166bd25394

Chemaclass
źródło