Que font les types stricts en PHP?

149

J'ai vu la nouvelle ligne suivante dans PHP 7, mais personne n'explique vraiment ce que cela signifie. Je l'ai googlé et tout ce dont ils parlent est de savoir si vous l'activez ou non comme un sondage.

declare(strict_types = 1);

Qu'est ce que ça fait? Comment cela affecte-t-il mon code? Devrais-je le faire?

Une explication serait bien.

sufuko
la source
5
Jetez un œil à cela aussi php.net/manual/en/… pour la directive
strict_types

Réponses:

154

Du blog Treehouse :

Avec PHP 7, nous avons maintenant ajouté des types scalaires. Plus précisément: int, float, string et bool.

En ajoutant des indices de type scalaire et en activant des exigences strictes, on espère que des programmes PHP plus corrects et auto-documentés pourront être écrits. Cela vous donne également plus de contrôle sur votre code et peut rendre le code plus facile à lire.

Par défaut, les déclarations de type scalaires ne sont pas strictes, ce qui signifie qu'elles tenteront de changer le type d'origine pour correspondre au type spécifié par la déclaration de type. En d'autres termes, si vous passez une chaîne qui commence par un nombre dans une fonction qui nécessite un flottant, elle récupérera le nombre depuis le début et supprimera tout le reste. Passer un flottant dans une fonction qui nécessite un int deviendra int (1).

Par défaut, PHP convertit les valeurs du mauvais type dans le type scalaire attendu si possible. Par exemple, une fonction qui reçoit un entier pour un paramètre qui attend une chaîne obtiendra une variable de type chaîne.

Types stricts désactivés ( 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)
  */

Il est possible d'activer le mode strict sur une base par fichier. En mode strict, seule une variable de type exact de la déclaration de type sera acceptée, ou une TypeError sera levée. La seule exception à cette règle est qu'un entier peut être donné à une fonction qui attend un float. Les appels de fonction depuis les fonctions internes ne seront pas affectés par la déclaration strict_types.

Pour activer le mode strict, l'instruction declare est utilisée avec la déclaration strict_types:

Types stricts activés ( 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

Exemple de travail:

<?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
la source
3
La première erreur fatale mentionnée dans votre exemple d'activation des types stricts est fausse. Comme mentionné dans la documentation: "La seule exception à cette règle est qu'un entier peut être donné à une fonction attendant un flottant." L'appel de fonction n'échouerait pas sur l'int. Ce serait sur la chaîne cependant.
Paul
63

strict_types affecte la coercition de type.

L'utilisation d'indices de type sans strict_typespeut conduire à des bogues subtils.

Avant les types stricts, int $xsignifiait " $xdoit avoir une valeur coercible à un int". Toute valeur qui pourrait être forcée à un intpasserait l'indicateur de type, y compris:

  • un int propre ( 242),
  • un flotteur ( 10.17),
  • un booléen ( true),
  • null, ou
  • une chaîne avec les premiers chiffres ( "13 Ghosts").

En définissant strict_types=1, vous indiquez au moteur que int $x"$ x ne doit être qu'un int proprement dit, aucune contrainte de type n'est autorisée." Vous avez la grande assurance d'obtenir exactement et uniquement ce qui a été donné, sans aucune conversion ni perte potentielle.

Exemple:

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

Donne un résultat potentiellement déroutant:

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

La plupart des développeurs s'attendraient, je pense, à un intindice signifiant "seulement un int". Mais ce n'est pas le cas, cela signifie "quelque chose comme un int". L'activation de strict_types donne le comportement attendu et souhaité probable:

<?php declare(strict_types=1);

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

Rendements:

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

Je pense qu'il y a deux leçons ici, si vous utilisez des indices de type:

  • Utilisez strict_types=1, toujours.
  • Convertissez les avis en exceptions, au cas où vous oublieriez d'ajouter le strict_typespragma.
évêque
la source
1
Cela a déjà été bien répondu comme il y a presque un an;)
emix
6
En effet, j'ai voté pour l'autre réponse @emix. Cependant, j'ai senti que la question «devrais-je le faire» n'a pas été abordée. J'ai également senti qu'un exemple plus compact et choquant encouragerait les gens à l'utiliser strict_types.
évêque
1
Je pense que cette question aborde succinctement le "Dois-je le faire?" partie de la question du PO. Revenir à PHP après une petite pause et cela a été très utile.
Darragh Enright