web-dev-qa-db-fra.com

Que font les types stricts en PHP?

J'ai vu cette nouvelle ligne en PHP7, mais personne n'explique vraiment ce que cela signifie. Je l'ai googlé et tout ce dont ils parlent est de savoir si vous allez l'activer 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.

71
sufuko

De blog Treehouse :

Avec PHP 7, nous avons maintenant ajouté des types Scalar. Spécifiquement: int, float, string et bool.

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

Par défaut, les déclarations de type scalaires ne sont pas strictes, ce qui signifie qu'elles tenteront de modifier le type d'origine afin qu'il corresponde 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, il prendra le nombre depuis le début et supprimera tout le reste. Passer un float dans une fonction qui nécessite un int devient int (1).

Par défaut, PHP convertira les valeurs du type incorrect dans le type scalaire attendu si possible. Par exemple, une fonction à laquelle un entier est attribué à un paramètre qui s'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 fichier par fichier. En mode strict, seule une variable du type exact de la déclaration de type sera acceptée ou une erreur TypeError sera renvoyée. La seule exception à cette règle est qu'un entier peut être donné à une fonction qui attend un float. Les appels de fonction à partir de 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 on 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');
81
azjezz

strict_types affecte type coercion.

Avant les types stricts, int $x signifiait "$x doit avoir une valeur similaire à un int, mais pas nécessairement un int approprié". Tout ce qui pourrait être contraint à un int correct passerait l'indicateur de type, y compris:

  • un int propre (242),
  • un float (10.17),
  • un bool (1),
  • null ou
  • une chaîne avec les premiers chiffres (13 Ghosts).

Maintenant, en réglant strict_types=1, vous indiquez au moteur que int doit signifier "exactement et uniquement un int correct". Rien d'autre. Vous avez une grande et grande assurance que vous obtenez exactement et uniquement ce qui a été donné, sans conversion ni perte potentielle.

Exemple:

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

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

Je pense que la plupart des développeurs s'attendent à ce qu'un indice int signifie "seulement un int". Mais ce n'est pas le cas, cela signifie "quelque chose comme un int". L'activation de types stricts 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 astuces de type:

  • Utilisez strict_types=1, toujours.
  • Convertissez les avis en exceptions, au cas où vous oublieriez d’ajouter le pragma strict_types.
24
bishop