Comme la plupart d’entre nous le savent, PHP est peu typé . Pour ceux qui ne le font pas, PHP.net dit:
PHP ne nécessite pas (ni ne prend en charge) la définition de type explicite dans la déclaration de variable; le type d'une variable est déterminé par le contexte dans lequel la variable est utilisée.
Qu'on l'aime ou qu'on le déteste, PHP redéfinit les variables à la volée. Donc, le code suivant est valide:
$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)
PHP vous permet également de convertir explicitement une variable, comme ceci:
$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"
C'est tout cool ... mais, pour ma vie, je ne peux pas concevoir une raison pratique pour cela.
Le typage fort ne me pose pas de problème dans les langages qui le prennent en charge, comme Java. C'est bien et je le comprends tout à fait. De plus, je suis conscient de l'utilité de l'indication de type dans les paramètres de fonction et comprend parfaitement son utilité .
Le problème que j'ai avec le casting de type est expliqué par la citation ci-dessus. Si PHP peut échanger des types à volonté , il peut le faire même après avoir forcé la conversion d' un type. et il peut le faire à la volée lorsque vous avez besoin d'un certain type d'opération. Cela rend valide ce qui suit:
$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"
Alors à quoi ça sert?
Prenons cet exemple théorique d'un monde où la conversion de types définie par l'utilisateur a un sens en PHP :
- Vous forcez la variable
$foo
deint
conversion comme →(int)$foo
. - Vous essayez de stocker une valeur de chaîne dans la variable
$foo
. - PHP lève une exception !! ← Cela aurait du sens. Tout à coup, la raison du transtypage défini par l'utilisateur existe!
Le fait que PHP modifie les choses selon les besoins rend vague le sens du type défini par l'utilisateur. Par exemple, les deux exemples de code suivants sont équivalents:
// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;
Un an après avoir posé cette question à l'origine, devinez qui s'est retrouvé à utiliser la conversion de texte dans un environnement pratique? Votre sincèrement.
L'exigence était d'afficher des valeurs monétaires sur un site Web pour un menu de restaurant. La conception du site nécessitait que les zéros de fin soient supprimés, de sorte que l'affichage ressemble à peu près à ce qui suit:
Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3
La meilleure façon que j'ai trouvée de le faire était de convertir la variable en float:
$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;
PHP élimine les zéros de fin du flottant, puis le remodèle en tant que chaîne pour la concaténation.
la source
(string)
moulages partout ?$intval.'bar'
jette une exception, je suis toujours en désaccord. Cela ne jette une exception dans aucune langue. (Toutes les langues que je connais effectuent une distribution automatique ou a.toString()
). Si vous dites$intval = $stringval
lève une exception, vous parlez d'un langage fortement typé. Je ne voulais pas avoir l'air impoli, alors, désolé si je l'avais fait. Je pense simplement que cela va à l’encontre de ce que chaque développeur est habitué et est beaucoup, beaucoup moins pratique.Réponses:
Dans un langage faiblement typé, le transtypage existe pour supprimer toute ambiguïté dans les opérations typées. Dans le cas contraire, le compilateur / interprète utiliserait un ordre ou d’autres règles pour supposer quelle opération utiliser.
Normalement, je dirais que PHP suit ce modèle, mais dans les cas que j'ai vérifiés, PHP s'est comporté de manière contre-intuitive dans chacun d'eux.
Voici ces cas, utilisant JavaScript comme langage de comparaison.
Concatentation de cordes
Évidemment, cela ne pose pas de problème en PHP car il existe des opérateurs de concaténation de chaînes (
JavaScript.
) et d'addition (+
) distincts .Comparaison de chaîne
Souvent, dans les systèmes informatiques, "5" est supérieur à "10" car il n'est pas interprété comme un nombre. Ce n’est pas le cas en PHP, qui, même s’ils sont tous deux des chaînes, réalise qu’ils sont des nombres et supprime le besoin de faire un casting):
JavaScript PHPDactylographie de signature de fonction
PHP implémente une vérification de type pure et simple sur les signatures de fonctions, mais malheureusement, il est tellement imparfait qu'il est probablement rarement utilisable.
Je pensais pouvoir faire quelque chose de mal, mais un commentaire sur la documentation confirme que des types intégrés autres que array ne peuvent pas être utilisés dans les signatures de fonctions PHP - bien que le message d'erreur soit trompeur.
PHPEt contrairement à tout autre langage que je connais, même si vous utilisez un type qu’il comprend, null ne peut plus être passé à cet argument (
must be an instance of array, null given
). Tellement stupide.Interprétation booléenne
[ Edit ]: Celui-ci est nouveau. J'ai pensé à un autre cas, et encore une fois, la logique est inversée à partir de JavaScript.
JavaScript PHPDonc, en conclusion, le seul cas utile auquel je puisse penser est ... (drumroll)
Type de troncature
En d'autres termes, lorsque vous avez une valeur d'un type (par exemple, chaîne) et que vous souhaitez l'interpréter comme un autre type (int) et que vous souhaitez le forcer à devenir l'un des ensembles de valeurs valides de ce type:
Je ne vois pas ce que l'upcasting (pour un type qui englobe plus de valeurs) pourrait vraiment vous gagner.
Ainsi, bien que je sois en désaccord avec l’utilisation que vous proposez de dactylographie (vous proposez essentiellement une dactylographie statique , mais avec l’ambiguïté voulant que c’est seulement si elle était moulée de force dans un type que cela jetterait une erreur - ce qui causerait de la confusion), je pense que c’est un bon question, car apparemment le casting a très peu de sens en PHP.
la source
E_NOTICE
alors? :)E_NOTICE
peut-être acceptable , mais pour moi, l'état ambigu est préoccupant. Comment savoir, en regardant un morceau de code, si la variable était dans cet état (après avoir été exprimée ailleurs)? En outre, j'ai trouvé une autre condition et l'a ajouté à ma réponse.echo "010" == 010
etecho "0x10" == 0x10
;-)Vous mélangez les concepts de type faible / fort et dynamique / statique.
PHP est faible et dynamique, mais votre problème réside dans le concept de type dynamique. Cela signifie que les variables n'ont pas de type, les valeurs en ont.
Un 'typage de type' est une expression qui produit une nouvelle valeur d'un type différent de l'original; cela ne fait rien à la variable (si on est impliqué).
La seule situation dans laquelle je tape régulièrement des valeurs de conversion se trouve dans les paramètres numériques SQL. Vous êtes censé supprimer / échapper toute valeur d'entrée que vous insérez dans des instructions SQL ou (encore mieux) utiliser des requêtes paramétrées. Mais si vous voulez une valeur qui DOIT être un entier, il est beaucoup plus facile de la lancer.
Considérer:
si je laissais de côté la première ligne, ce
$id
serait un vecteur facile pour l'injection SQL. La distribution s'assure que c'est un entier inoffensif; toute tentative d’insertion de SQL aboutirait simplement à une requêteid=0
la source
mysql_real_escape_string($id);
elle pas déjà?mysql_real_escape_string()
est vulnérable à ne rien faire avec des chaînes telles que '0x01ABCDEF' (c'est-à-dire la représentation hexadécimale d'un entier). Dans certains encodages multi-octets (pas Unicode heureusement), une chaîne comme celle-ci peut être utilisée pour casser la requête (car elle est évaluée par MySQL avec quelque chose qui contient un guillemet). C'est pourquoi ni le meilleur choixmysql_real_escape_string()
niis_int()
pour le traitement des valeurs entières. Typecasting est.Une utilisation que j'ai trouvée
pour la saisie de texte en PHP: Je développe une application Android qui envoie des requêtes http à des scripts PHP sur un serveur afin de récupérer des données d'une base de données. Le script stocke les données sous la forme d'un objet PHP (ou d'un tableau associatif) et est renvoyé sous forme d'objet JSON à l'application. Sans transtypage, je recevrais quelque chose comme ceci:
Mais, en utilisant le transtypage de type PHP
(int)
sur l'identifiant de l'utilisateur lors du stockage de l'objet PHP, je reçois plutôt ceci retourné à l'application:Ensuite, lorsque l'objet JSON est analysé dans l'application, cela m'évite d'avoir à analyser l'ID d'un entier.
Voir, très utile.
la source
Un exemple est des objets avec une méthode __toString:
$str = $obj->__toString();
vs$str = (string) $obj;
. Il y a beaucoup moins de dactylographie dans la seconde, et le plus important est la ponctuation, qui prend plus de temps à taper. Je pense aussi que c'est plus lisible, même si d'autres peuvent ne pas être d'accord.Un autre fait un tableau à un seul élément:
array($item);
vs(array) $item;
. Cela placera n'importe quel type scalaire (entier, ressource, etc.) dans un tableau.De manière alternative, si
$item
est un objet, ses propriétés deviendront des clés pour leurs valeurs. Cependant, je pense que la conversion objet-> tableau est un peu étrange: les propriétés privées et protégées font partie du tableau et sont renommées. Pour citer la documentation PHP : les variables privées ont le nom de la classe précédé du nom de la variable; Les variables protégées ont un '*' ajouté au nom de la variable.Une autre utilisation consiste à convertir les données GET / POST en types appropriés pour une base de données. MySQL peut gérer cela lui-même, mais je pense que les serveurs plus compatibles ANSI pourraient rejeter les données. La raison pour laquelle je ne parle que de bases de données est que, dans la plupart des autres cas, les données subissent une opération effectuée en fonction de leur type à un moment donné (c’est-à-dire que les calculs int / floats sont généralement effectués, etc.).
la source
int
oufloat
se produira lors de la construction de la requête).(array) $item
est soigné , mais utile?Ce script:
fonctionnera correctement
script.php?tags[]=one
mais échouerascript.php?tags=one
car_GET['tags']
retourne un tableau dans le premier cas mais pas dans le second. Étant donné que le script est écrit pour s’attendre à un tableau (et que vous avez moins de contrôle sur la chaîne de requête envoyée au script), le problème peut être résolu en convertissant le résultat de manière appropriée_GET
:la source
Il peut également être utilisé comme une méthode rapide et compliquée pour garantir que des données non fiables ne vont pas casser quelque chose, par exemple si vous utilisez un service distant qui a une validation de la merde et doit accepter uniquement les chiffres.
Évidemment, cela est erroné et également traité implicitement par l'opérateur de comparaison dans l'instruction if, mais il est utile pour vous permettre de savoir exactement ce que votre code est en train de faire.
la source
$_POST['amount']
contenait une chaîne de caractères, php évaluerait qu'elle n'est pas supérieure à zéro. Si elle contenait une chaîne représentant un nombre positif, elle serait évaluée comme étant vraie.L'une des "utilisations" des variables de reconfiguration PHP à la volée que je vois souvent utilisées consiste à récupérer des données à partir de sources externes (entrée utilisateur ou base de données). Cela permet aux codeurs (notez que je n'ai pas dit les développeurs) d' ignorer (ou même de ne pas apprendre) les différents types de données disponibles à partir de différentes sources.
Un codeur (notez que je n’ai pas dit développeur) dont le code dont j’ai hérité et que je maintiens toujours ne semble pas savoir qu’il existe une différence entre la chaîne
"20"
renvoyée dans la$_GET
super variable, entre l’opération d’entier20 + 20
quand elle l’ajoute la valeur dans la base de données. Elle n'a que de la chance que PHP utilise.
pour la concaténation de chaînes et pas+
comme toutes les autres langues, car j'ai vu son code "ajouter" deux chaînes (unevarcahr
de MySQL et une valeur de$_GET
) et obtenir un int.Est-ce un exemple pratique? Seulement dans le sens où cela laisse les codeurs s'en tirer sans savoir quels types de données ils utilisent. Personnellement, je le déteste.
la source