Cosa fanno i tipi rigorosi in PHP?


148

Ho visto la seguente nuova linea in PHP 7, ma nessuno spiega davvero cosa significhi. L'ho cercato su Google e tutto ciò di cui parlano è che lo abiliti o meno come un tipo di sondaggio.

declare(strict_types = 1);

Che cosa fa? In che modo influisce sul mio codice? Dovrei farlo?

Qualche spiegazione sarebbe buona.



5
.prova anche questo php.net/manual/en/… per la direttiva strict_types
scaisEdge,

Risposte:


153

Dal blog Treehouse :

Con PHP 7 ora abbiamo aggiunto tipi scalari. In particolare: int, float, string e bool.

Aggiungendo suggerimenti di tipo scalare e consentendo requisiti rigorosi, si spera che si possano scrivere programmi PHP più corretti e autocompattanti. Ti dà anche un maggiore controllo sul tuo codice e può renderlo più facile da leggere.

Per impostazione predefinita, le dichiarazioni di tipo scalare sono non rigide, il che significa che tenteranno di modificare il tipo originale in modo che corrisponda al tipo specificato dalla dichiarazione di tipo. In altre parole, se passi una stringa che inizia con un numero in una funzione che richiede un float, prenderà il numero dall'inizio e rimuoverà tutto il resto. Passare un float in una funzione che richiede un int diventerà int (1).

Per impostazione predefinita, PHP eseguirà il cast dei valori del tipo errato nel tipo scalare previsto, se possibile. Ad esempio, una funzione a cui viene assegnato un numero intero per un parametro che prevede una stringa otterrà una variabile di tipo stringa.

Tipi rigorosi disabilitati ( valutazione ):

<?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)
  */

È possibile abilitare la modalità rigorosa in base al file. In modalità rigorosa, verrà accettata solo una variabile del tipo esatto della dichiarazione del tipo o verrà generato un errore TypeError. L'unica eccezione a questa regola è che un intero può essere assegnato a una funzione in attesa di un float. Le chiamate di funzione all'interno di funzioni interne non saranno influenzate dalla dichiarazione strict_types.

Per abilitare la modalità rigorosa, l'istruzione declare viene utilizzata con la dichiarazione strict_types:

Tipi rigorosi abilitati ( valutazione ):

<?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

Esempio funzionante:

<?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
Il primo errore fatale menzionato nell'esempio abilitato per i tipi rigorosi è errato. Come menzionato nella documentazione: "L'unica eccezione a questa regola è che un numero intero può essere assegnato a una funzione in attesa di un float". La chiamata di funzione non fallirebbe sull'int. Sarebbe sulla corda però.
Paul,

63

strict_types influenza la coercizione del tipo.

L'uso di suggerimenti di tipo senza strict_typespuò portare a bug sottili.

Prima di tipi rigorosi, int $xsignificava " $xdeve avere un valore coercibile a un int". Qualsiasi valore che potrebbe essere costretto a intpassare un suggerimento di tipo, incluso:

  • un int proprio ( 242),
  • un float ( 10.17),
  • un bool ( true),
  • null, o
  • una stringa con cifre iniziali ( "13 Ghosts").

Impostando strict_types=1, dici al motore che int $xsignifica "$ x deve essere solo un int proprio, nessuna coercizione di tipo consentita". Hai la certezza di ottenere esattamente e solo ciò che ti è stato dato, senza alcuna conversione e potenziale perdita.

Esempio:

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

Produce un risultato potenzialmente confuso:

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

La maggior parte degli sviluppatori si aspetterebbe, credo, che un intsuggerimento significhi "solo un int". Ma non lo fa, significa "qualcosa come un int". L'abilitazione di strict_types fornisce il comportamento probabile previsto e desiderato:

<?php declare(strict_types=1);

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

I rendimenti:

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

Penso che ci siano due lezioni qui, se usi i suggerimenti sul tipo:

  • Usa strict_types=1sempre.
  • Converti le notifiche in eccezioni, nel caso in cui dimentichi di aggiungere il strict_typespragma.

1
Questo ha già ricevuto una risposta come quasi un anno fa;)
emix

6
In effetti, ho votato a favore dell'altra risposta @emix. Tuttavia, ho sentito che la domanda "dovrei farlo" non è stata toccata. Ho anche sentito che un esempio più compatto e scioccante incoraggerebbe le persone a usare strict_types.
vescovo,

1
Penso che questa domanda si rivolga brevemente al "Dovrei farlo?" parte della domanda del PO. Ritornare a PHP dopo un po 'di pausa e questo è stato molto utile.
Darragh Enright,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.