JeuWeb - Crée ton jeu par navigateur
Le typage en PHP - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Le typage en PHP (/showthread.php?tid=3323)



Le typage en PHP - Ekilio - 20-11-2008

Donc, allons-y ! Du typage en PHP et comment l'utiliser.

Vous le savez probablement, PHP n'est pas un langage typé. Par ce terme, on entends qu'il n'est pas nécessaire, contrairement à la plupart des langages (au hasard, C, C++, Visual Basic...) de définir le type des variables, et donc de définir quelle catégories de données elles peuvent accueillir.

C'est une facilité de programmation pour nous, programmeurs, mais c'est aussi une faille de sécurité très importantes. C'est pourquoi il est nécessaire, pour assurer la sécurité d'une application web (au hasard, un jeu...) d'utiliser un typage strict, c'est à dire de savoir précisément, à tout moment, quel type de valeur contient une variable.

Les différents types

Même si PHP ne demande pas de typage explicite, il gère de manière interne plusieurs types de variables différents. Je les rappellent rapidement ; pour plus de détails, voir le chapitre types du manuel PHP.

Types basiques

Les types les plus simples sont au nombre de quatre. Basiquement, une variable de l'un de ces types est une variable contenant une seule valeur. Il y en a quatre :

Boolean

Les Boolean (ou booléens en français) sont les valeurs binaires ; il y a donc deux valeurs possibles pour une variable de ce type, true et false.

Entiers

Les nombres entiers sont des... nombres entiers ! Ils sont signés par défaut (php ne supporte pas les entiers non signés), ce qui signifie qu'ils peuvent aller dans les nombres négatifs (en d'autres termes, -1 n'est pas égal à 1, alors que dans le cas d'entiers non-signés, -1 n'a pas de sens et est égal à 1).

Il faut noter qu'il existe une valeur maximum pour un entier, c'est à dire un chiffre au-delà duquel un nombre ne sera plus un nombre entier mais un nombre à virgule flottante. Ce nombre varie selon les systèmes d'exploitations, mais en général il est un peu au-dessus de 2 milliard (c'est la taille d'un entier codé sur 32 bits). Pour connaitre la taille maximum d'un entier sur votre système, il suffit de regarder la variable PHP_INT_MAX.

Les entiers peuvent être définis de plusieurs manières, en fonction de la base que l'on souhaite employer (ceux qui sont en spé maths vont adorer). Notez que l'affichage se fait toujours en base 10 lorsqu'on fait un echo :

- En tant qu'entier normal, base décimal donc :

Code PHP :
<?php
$entier
= 12;
echo
$entier; // Affichera 12
$entier = -3;
echo
$entier; // Affichera -3
?>

- En tant qu'entier en base octal, donc en base 8 (0 1 2 3 4 5 6 7 10 11 12 13 etc.) ; dans ce cas il faut faire précéder notre entier par un 0 :

Code PHP :
<?php
$entier
= 012;
echo
$entier; // Affichera 10
?>

- En tant qu'entier hexadécimal, donc en base 16 (0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 etc.) ; dans ce cas il faut faire préceder notre entier par 0x :

Code PHP :
<?php
$entier
= 0xFF;
echo
$entier; // Affichera 255
?>

Nombre à virgule flottante

Les nombres à virgule flottante (float ou double) sont des nombres avec... une virgule. Notez qu'un nombre à virgule peut être entier, à condition qu'il soit écrit avec une virgule : 10.0 est un nombre à virgule, 10 est un entier.

Il n'y a pas de limite à la taille des float, contrairement aux entiers (sauf la capacité maximum de ram de votre ordinateur, mais bon...).

Notez que le résultat de n'importe quelle division d'entiers qui ne tombe pas juste est un nombre à virgule flottante.

Exemple :
Code PHP :
<?php
$entier
= 10; // Entier
$float = 10.0; // Float
$float = 13.44; // Float
$float = -3.23456; // Float
$float = 1/2; // Float
?>

Chaines de caractères

Le dernier type de variables de PHP sont les chaines de caractères. En gros, une chaine de caractère est un ensemble de chiffres ou lettres. Notez que avant la version 6, PHP ne supporte pas l'unicode, il y a donc uniquement 256 caractères différents possibles dans une chaine de caractère. Et cela n'inclue pas les accents ; le comportement de PHP est donc imprévisible si vous voulez utiliser certaines fonctions, particulièrement serialize, sur une chaine contenant des accents.

Une chaine de caractères peut être définie de quatre manières différentes. Je ne m'intéresserait pas ici aux performances de ces différentes manières (mais la plus rapide, toutes situations confondues, est ', voir ces benchmarks, même si le seul cas où c'est réellement plus rapide est très rare dans la réalité).

La première manière est à l'aide des guillemets simples ; dans cette syntaxe, les variables ne sont pas interprétés :

Code PHP :
<?php
$boisson
= 'San Pellegrino';
$texte = 'Ma boisson préférée est la $boisson';
echo
$texte; // Affichera Ma boisson préférée est la $boisson
?>

La seconde manière est en utilisant des guillements doubles ; dans cette syntaxe, les variables sont interprétés :

Code PHP :
<?php
$boisson
= 'San Pellegrino';
$texte = "Ma boisson préférée est la $boisson";
echo
$texte; // Affichera Ma boisson préférée est la San Pellegrino
?>

Notez qu'il est possible de passer des choses bien plus complexes dans une chaine de caractères avec des guillemets double (voir la documentation pour tous les détails), particulièrement des appels à des fonctions ou à des tableaux à l'interieur même des chaines :

Code PHP :
<?php
$boisson
['eau gazeuse'] = 'San Pellegrino';
$texte = "Ma boisson préférée est la {$boisson['eau gazeuse']}";
echo
$texte; // Affichera Ma boisson préférée est la San Pellegrino
?>

La troisième manière est la syntaxe nommée HereDoc. Elle fonctionne comme les guillemets doubles, à ceci près qu'elle accepte plusieurs lignes :

Code PHP :
<?php
$boisson
= 'San Pellegrino';
$texte = <<<TEXTE
Mon texte viens ici.
Il peut parler de
$boisson et prendre plusieurs lignes.
TEXTE;
echo
$texte;
?>

Je vous laisse faire le test, mais en gros, ça affichera le texte en remplaçant $boisson par la marque d'eau gazeuse. Notez que cette syntaxe doit respecter un format très strict : trois <, puis un identifiant, puis un retour à la ligne. Puis le texte. Et à la fin du texte, une nouvelle ligne, l'identifiant sans indentation, et un point-virgule.

L'avantage principal de cette syntaxe est qu'il n'est pas nécessaire de passer par des caractères spéciaux (\n) même si ils sont toujours utilisables, et qu'il n'est pas nécessaire d'échapper les apostrophes.

Enfin, la dernière syntaxe, introduite en PHP 5.3.0 (qui est actuellement en alpha, et donc que vous n'avez probablement pas sur vos hébergeurs, mais j'en parle quand même) est la syntaxe NowDoc. En gros, c'est un mélange entre les guillemets simples et la syntaxe HereDoc : les variables n'y sont pas interprétés, mais la chaine se présente comme une chaine HereDoc, à ceci près que l'identifiant est entre guillements.

Voici un exemple :

Code PHP :
<?php
$boisson
= 'San Pellegrino';
$texte = <<<'TEXTE'
Mon texte viens ici.
Il peut parler de $boisson et prendre plusieurs lignes.
TEXTE;
echo
$texte;
?>

Type complexes

Les types complexes sont constitués de plusieurs éléments de types basiques. Ils sont au nombre de deux : les tableaux et les objets. Détailler leurs fonctions dépasserait largement le but de ce tutoriel, donc je n'en parlerais pas ; sachez que de toutes façons, les conversions d'un type complexe à un type basique ne sont globalement pas supportés par PHP, sauf dans un cas que je traiterais, et que vous obtiendrez une erreur fatale si vous tentez de le faire, par exemple ainsi :

Code PHP :
<?php
$entier
= 3;
$table = array(3);
echo
$entier * $table;
?>

Type spéciaux

Il existe enfin deux type "spéciaux", qui ne rentrent dans aucun des autres types :

Le type NULL

Le type NULL représente une variable qui n'a aucune valeur ; la seule valeure possible d'une variable de type NULL est NULL. Attention à ne pas confondre NULL et 0 : 0 est une valeur, NULL non. De même, '' est une valeur, et n'est donc pas NULL.

Le type resource

Les resource (ressource en français) sont des variables spéciales qui contiennent simplement un lien vers un gestionnaire ou une application externe. Les deux exemples les plus simples sont le résultat de la fonction mysql_connect(), qui est une ressource mysql liant vers une connexion ouverte, et le résultat de la fonction fopen(), qui est une ressource de liant vers un pointeur dans un fichier.

Théoriquement, vous ne devriez jamais faire de manipulation de type sur une ressource. Sachez néanmoins que vous pouvez essayer, et que ça ne posera pas de problèmes particuliers à PHP (par contre, probablement à votre application), les ressources étant aussi considérées comme des chaines de caractères.

Autres types

J'en profite pour signaler qu'il existe trois autres types de variables qu'on peut rencontrer dans la documentation mais qui n'existe pas réellement en php ; elles ne sont là dans les fonctions que pour aider à la lecture. Ce sont :

- mixed qui indique que la fonction accepte (ou renvoi) différents types (mais pas forcément tous)
- number qui indique que le paramètre attendu est un nombre entier ou un nombre à virgule flottante
- callback qui indique que le paramètre attendu est une fonction.

Conversions de types

Maintenant qu'on a bien défini les différents types de variables en PHP, voyons un peu comment les convertir. Il y a beaucoup de cas où on peut vouloir passer une variable d'un type à l'autre, le plus simple étant lorsqu'on a une donnée d'un type inconnu et qu'on souhaite lui donner un type fixe.

Il y a globalement deux types de conversions : celles où on sait ce qu'on veux obtenir et celles où on y a pas réflechit.

Quand on sait ce qu'on veux obtenir, c'est assez simple : il suffit de le demander. PHP propose une syntaxe nommée le casting qui permet de spécifier un type, et hop ! Notre variable sera transformée en ce type.

Je ne vais parler ici d'une manière détaillée que des quatres types basiques.

Tout d'abord, voici comment faire :

Code PHP :
<?php
$booleen
= (bool) $variable; // $booleen contiendra un booléen
$entier = (int) $variable; // $entier contiendra un entier
$float = (float) $variable; // $float contiendra un nombre à virgule flottante
$string = (string) $variable; // $string contiendra une chaine de caractères
$null = (unset) $variable; // $variable contiendra NULL
?>

(Notez qu'il est également possible de faire de même avec (array) pour les tableaux et (object) pour les objets)

Voyons un peu ce qu'il adviendra de nos variables quand on les convertit :

Booléen

Lorsqu'on convertit une variable en booléen, c'est simple. Si la variable est dans l'un des cas suivants, le booléen obtenu vaudra FALSE, sinon il vaudra TRUE :

- Le booléen FALSE, bien sûr
- L'entier 0
- Le nombre à virgule flottante 0.0
- La chaine de caractère vide ''
- La chaine de caractère '0'
- Un tableau sans aucun élément (array())
- Un objet sans aucun membre et sans aucune variable
- N'importe quelle variable de type NULL
- Certains objets SimpleXML

Toutes les autres variables, converties en booléen, donneront true.

Les entiers

Là, on rentre dans un domaine un peu plus compliqué. La valeur obtenue lors de la conversion en entier dépends du type de départ :

- Si la valeur est de type booléen avant sa conversion, la variable obtenue vaudra 1 si la valeur était TRUE et 0 si la valeur était FALSE

- Si la valeur est de type entier à virgule flottante avant sa conversion, la variable obtenue sera la partie entière de cette valeure (10.3 donnera 10), arrondie à l'inferieur.

Quelques avertissement ici : si le float est trop grand pour être arrondi (superieur à 2 milliard et des poussières), alors le comportement sera aléatoire et ne donnera pas d'avertissement. Donc à ne jamais, jamais faire.

De plus, la conversion d'une fraction en entier peut donner des résultats bizarres :

Code PHP :
<?php
echo (int) ((0.1 + 0.7) * 10); // Affiche 7
?>

Donc toujours faire les calculs avant la conversion.

- Si la valeur avant la conversion est une chaine de caractères, la valeur est un peu plus complexe. Voir le manuel pour une autre façon de le dire, mais en gros :

* Si la chaine de caractères contient l'un des caractères suivants : '.', 'e' ou 'E', elle sera évaluée comme un nombre à virgule flottante, et ensuite convertie en entier. Sinon, elle sera évaluée comme un entier.

* C'est le début de la chaine qui donne la valeur de l'entier. Si le début de la chaine est un caractère valide pour un entier (donc 0 ou n'importe quel autre chiffre, ou le signe + ou le signe -), alors cela va donner la valeur, sinon, la valeur obtenu sera 0.

* Si le premier caractère est valide, alors la chaine sera lue jusqu'au premier caractère invalide (c'est à dire qui n'est ni un chiffre, ni le . qui sert de virgule, ni l'exponentiel e), ou jusqu'à la fin de la chaine.

Attention aux amateurs de C, convertir un caractère en entier ne vous donnera pas son code ASCII.

- Enfin, la conversion de n'importe quel autre type (ressource, objet, tableau ou NULL) en entier est totalement aléatoire, et peut aussi bien faire venir une erreur fatale que donner un résultat au hasard. Vous l'aurez compris, c'est à ne jamais faire.

Quelques exemples de conversions en entier :

Code PHP :
<?php
$variable
= (int) 3; // Donnera un entier (3)
$variable = (int) 3.0; // Donnera un entier (3)
$variable = (int) 3.1; // Donnera un entier (3)
$variable = (int) 3.9; // Donnera un entier (3)
$variable = (int) false; // Donnera un entier (0)
$variable = (int) 'Ma chaine de caractères'; // Donnera un entier (0)
$variable = (int) '12 Ma chaine de caractères'; // Donnera un entier (12)
$variable = (int) '3.2 Bonjour !'; // Donnera un entier (3)
$variable = (int) 'Bonjour ! 3'; // Donnera un entier (0)
$variable = (int) NULL; // Plantera !
$variable = (int) array(); // Plantera aussi !
?>

Les nombres à virgule flottante

La conversion en nombre à virgule flottante est assez simple. Dans le cas d'un entier, on prends simplement cet entier et on le "considère" comme un nombre à virgule flottante (10 devient 10.0, par exemple).

Dans le cas de n'importe quel autre type de variable, on la converti en entier (si c'est possible, sinon ça plante) et ensuite on converti cet entier en nombre à virgule flottante.

Seule exception : les chaines de caractères seront directement converties en nombre à virgule flottante si possible (donc si elles contiennent l'un des caractères suivants : '.', 'e' ou 'E').

Les chaines de caractères

La conversion en chaine de caractère est encore plus simple. Pour résumer, convertir une variable, quelle qu'elle soit, en chaine de caractères, c'est faire ceci :

Code PHP :
<?php
$variable
= "$monAncienneVariable";
?>

Opérations sur les variables de types différents

Comme je le disais plus haut, il arrive aussi parfois qu'on fasse une conversion sans trop réflechir à ce qu'elle va donner. L'exemple type est lorsqu'on souhaite faire ceci :

Code PHP :
<?php
// $_POST['toto'] = 'Bonjour !';
echo 3 * $_POST['toto'];
?>

Le principe est alors très simple : PHP va opérer à une conversion de type automatique, et résoudre ensuite le calcul.

La conversion de type est faite de manière à obtenir un résultat perdant le moins d'informations possibles. Ce qui implique que :

- Dans le cas d'utilisation de l'opérateur de concaténation (.), les variables seront toutes converties en chaines de caractères :

Code PHP :
<?php
$texte
= 'Bonjour';
$integer = 3;
var_dump($texte . $integer); // Affichera string(8) "Bonjour3"
?>

- Dans le cas de l'utilisation d'un opérateur mathématique n'amenant pas de nombre à virgule (+ - *), les deux éléments seront convertis en numériques (donc en nombre à virgule éventuellement, dans le cas d'une chaine de caractères contenant l'un des caractères '.', 'e' ou 'E', et sinon en entier)

* Un nombre à virgule si l'un des deux éléments (ou sa conversion) est un nombre à virgule :

Code PHP :
<?php
$variable
= 12.3 + 1; // Float : 13.3
$variable = 1.0 + 1; // Float : 2.0
$variable = '2.0 Bonjour' + 1; // Float : 3.0
?>

* Un nombre entier si aucun des deux éléments (ou leurs conversion) n'est un nombre à virgule :

Code PHP :
<?php
$variable
= 1 + 1; // Entier : 2
$variable = '2 petits cochons' + 2; // Entier : 4
$variable = '2 petits cochons' - '1 roti de porc'; // Entier : 1
$variable = 1 + 'Bonjour ! 1'; // Entier : 1
?>

- Dans le cas d'un opérateur mathématique pouvant amener un nombre à virgule flottante (en d'autres termes, d'une division : /), si le résultat tombe juste, alors les mêmes règles que pour les autres opérateurs s'appliqueront ; sinon, le résultat sera un nombre à virgule flottante :

Code PHP :
<?php
$variable
= 4 / 2; // Entier : 2
$variable = 5 / 2; // Float : 2.5
$variable = '4 Dents' / 2; // Entier : 2
?>

Voila, j'espère que tout ceci vous aura permis de voir un peu quels sont les types d'entiers et les résultats de leurs combinaisons...

Mes deux centimes du soir,

Ekilio


RE: Le typage en PHP - zeppelin - 21-11-2008

super tuto, rien à redire! Si ce n'est expliquer vite fait comment comparer des variables et / ou des valeurs (strict ===, ou ==), c'est un domain que peu de monde comprends vraiment, je pense que ça peu en aider plus d'un ;-)

exemple: if(0 == null) est true, mais if(0 === null) est false

ps. Je vais donner des cours en PHP à des apprentis, puis-je te prendre certaines partie du code? :amoureux2:


RE: Le typage en PHP - Ekilio - 21-11-2008

Prends tout ce que tu veux :-) Tout ce que je publie ici est libre. J'ai la flemme de relire toutes les licences pour savoir exactement laquelle, mais en gros vous pouvez en faire ce que vous voulez ; si vous le reproduisez sur internet, me dire où et me citer ça me fait toujours plaisir mais ce n'est même pas obligatoire :-) Donc n'hésites pas pour les apprentis, prends :-)


RE: Le typage en PHP - keke - 21-11-2008

Ca vaut plus que 2 centimes ^^

Merci pour l'info sur les HereDoc :
Code :
<?php
$boisson = 'San Pellegrino';
$texte = <<<TEXTE
Mon texte viens ici.
Il peut parler de $boisson et prendre plusieurs lignes.
TEXTE;
echo $texte;
?>

Que j'ignorais totalement ^^

Kéké


RE: Le typage en PHP - Plume - 21-11-2008

  • C'est quoi l'intérêt de la NowDoc(que je ne connaissais pas) comparée à la HereDoc(que je connais et qui est über cool) ?
  • Très intéressant, même si trouvable et déjà connu, mais je m'attendais à trouver au moins une organisation, norme de nommage pour aider les néophytes à ne pas se tromper. Parce que là, la faille est plus ou moins toujours présente.

P.


RE: Le typage en PHP - arcanis - 21-11-2008

Citation :C'est quoi l'intérêt de la NowDoc(que je ne connaissais pas) comparée à la HereDoc(que je connais et qui est über cool) ?
La même qu'entre les simples quotes et les doubles quotes:
Code :
$test = 42;
echo "$test"; // affiche 42
echo '$test'; // affiche "$test"

Heredoc est un synonyme des doubles quotes et Nowdoc un synonyme des simples quotes.

Citation :Parce que là, la faille est plus ou moins toujours présente.
Laquelle ?


RE: Le typage en PHP - Plume - 21-11-2008

Ben qu'on sache comment est typée une variable suivant son contenu ça ne veut pas dire qu'en voyant juste la variable je vais savoir quel type elle a. J'me fais comprendre ?

P.


RE: Le typage en PHP - z3d - 23-11-2008

Je rejoins tout le monde sur la qualité du tutoriel. Il est vrai que le très faible typage du PHP a permis son développement, fulgurant soit dit en pensant mais celui-ci nous pose de sacré problème toutefois si on manque un poil d'attention; l'apparition de l'opérateur triple égale (===) vient justement rustiner ce très faible typage.

@Plume > On se lance, il me semble, dans un tout autre sujet qui est un problème connu de tout langage. Cette étape, la convention de nommage, intervient après la notion de typage. J'adore le "CamelCase typé".
Code PHP :
<?php 
/**
* une chaîne (String)
*/
$sFirstName = 'Dupont';
$sLastName = 'Lajoie';

/**
* un tableau (Array)
*/
$aTable = array();
$aTableNew = array();
$aTableOld = array();

// etc.



RE: Le typage en PHP - Plume - 23-11-2008

Je trouvais juste que malgré la qualité du contenu actuel, il manquait une étape. Ce manque est surtout dû à l'introduction :
Citation :C'est une facilité de programmation pour nous, programmeurs, mais c'est aussi une faille de sécurité très importantes.
Il y parle de faille de sécurité et j'm'attendais donc à trouver une façon de repérer le type d'une variable car le fait de savoir comment est typée une variable, c'est pas suffisant.

Evidemment, je ne m'attendais pas à y consacrer une grosse partie Smile

Citation :J'adore le "CamelCase typé".
J'en suis aussi Smile

Code :
+------------+---------+-------------+
| Type       | Préfixe | Exemple     |
+------------+---------+-------------+
| array      | arr     | $arrExemple |
| binary     | bin     | $binExemple |
| boolean    | boo     | $booExemple |
| double     | dbl     | $dblExemple |
| date       | dat     | $datExemple |
| float      | flt     | $fltExemple |
| integer    | int     | $intExemple |
| object     | obj     | $objExemple |
| string     | str     | $strExemple |
| record set | rs      | $rsExemple  | - exception sur 2 lettres
| unset      | ust     | $ustExemple |
+------------+---------+-------------+

AMHA,
P.