ctype

Mammouth du PHP | 768 Messages

03 avr. 2006, 23:12

Messieurs dames,
j'ai lu avec grand interet la documentation PHP concernant les fonctions ctype
extrait de la doc:
Il est à noter que les fonctions ctype sont toujours préférables par rapport aux expressions rationnelles ainsi que les fonctions équivalentes str_* et is_*. Les fonctions ctype utilisent une bibliothèque C native qui les rendent bien plus rapides.
Adieu les PCRE pour des vérifications basiques tel que is_numeric par exemple :lol:
Je ne sais pas comment j'ai pu passer à coté de ça, et je trouvais intéressant d'en discuter ici :wink:
M A R I O
Si une patte de lapin porte bonheur, qu'a-t-il bien pu arriver au lapin ?

Mammouth du PHP | 19672 Messages

04 avr. 2006, 07:54

C'est effectivement très intéressant, mais de là à reléguer les expressions régulières au rang des techniques périmée,s, il y a une marge. En revanche, ça peut s'avérer d'une utilité non négligeable si on combine ces fonctions avec les vérifications par expressions régulières. Les fonctions ctype présentent tout de même quelques limites, mais elles peuvent être plus intéressantes dans des cas où l'utilisation des regexp est peut-être exagérée. Il faudrait faire quelques benchmarks pour comparer :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

04 avr. 2006, 09:42

Qui qui se dévoue pour bencher
for ($i=0; $i<999999; $i++)
  $res = is_numeric($i);
for ($i=0; $i<999999; $i++)
  $res = ctype_digit($i);
for ($i=0; $i<999999; $i++)
  $res = preg_match('/^\d+$/',$i);
Je n'aurai personnellement pas l'environnement adéquat avant ce soir.

Mammouth du PHP | 19672 Messages

04 avr. 2006, 11:22

OK, code exécuté comme suit:
<?php
$a = microtime(true);
for ($i=0; $i<999999; $i++)
{
    $res = is_numeric($i);
}
$b = microtime(true);
for ($i=0; $i<999999; $i++)
{
    $res = ctype_digit($i);
}
$c = microtime(true);
for ($i=0; $i<999999; $i++)
{
    $res = preg_match('/^\d+$/',$i);
}
$d = microtime(true);
$duree_isnum = $b - $a;
$duree_ctype = $c - $b;
$duree_preg  = $d - $c;

?>
<p>Durée d'exécution avec "is_numeric" : <?php echo($duree_isnum); ?> sec.</p>
<p>Durée d'exécution avec "ctype_digit" : <?php echo($duree_ctype); ?> sec.</p>
<p>Durée d'exécution avec "preg_match" : <?php echo($duree_preg); ?> sec.</p>
Résultat sur ma machine :
Durée d'exécution avec "is_numeric" : 0.407069921494 sec.

Durée d'exécution avec "ctype_digit" : 1.15200304985 sec.

Durée d'exécution avec "preg_match" : 4.02198886871 sec.
Dans les choux le preg_match, mais is_numeric passe malgré tout devant :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Avatar du membre
Administrateur PHPfrance
Administrateur PHPfrance | 13231 Messages

04 avr. 2006, 13:33

Dans les choux le preg_match, mais is_numeric passe malgré tout devant :-k
et largement devant

Heureusement que la fonction native est censée fonctionner plus rapidement :roll:
Connaître son ignorance est la meilleure part de la connaissance
Pour un code lisible : n'hésitez pas à sauter des lignes et indenter

twitter - site perso - Github - Zend Certified Engineer

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

04 avr. 2006, 20:00

En effet, ctype est une extension très utile et très rapide donc chaque fois que c'est possible je l'utilise à la place d'un preg_match()

Attention aux comparaisons entre ctype_digit et is_numeric, ils ne font pas la même chose!
  • ctype_digit: /^[0-9]+$/ (ou /^\d+$/)
  • is_numeric: /^\-?[0-9]+(\.[0-9]+)?(e[0-9]*[+\-]?[0-9]+)?$/
Par exemple, -1.2e+3 est un nombre (notation scientifique) donc is_numeric() renvoit TRUE, mais ctype_digit() renvoit FALSE car il n'est pas exclusivement composé de chiffres.

D'autres optimisations sur ilia.ws

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

04 avr. 2006, 20:13

Après vérification, il s'avère que is_numeric() triche pour être premier. Comment fait-il ? Facile, il vérifie si le type de l'argument qu'on lui passe et si c'est un (int) alors il renvoit TRUE immédiatement. Il faudrait par conséquent utiliser un benchmark légèrement différent, par exemple:
$i = 1000000;
do
{
	is_numeric((string) $i);
}
while (--$i);
Ou même mieux, remplacer (string) $i par '12345' pour éviter de passer du temps à changer le type de $i.

Invité
Invité n'ayant pas de compte PHPfrance

04 avr. 2006, 21:25

si on veut chipoter déjà is_numeric c'est pour les int et autres floats ou doubles.
donc la comparaison devrait se faire avec is_integer...

mais le plus important c'est que les ctype_xxx ne fonctionne qu'avec des chaînes ($a=1;ctype_digit($a) renverra faux contrairement à $a="1"; ctype_digit($a)).

avec is_integer c'est l'inverse...mais pas avec is_numeric qui se fout de recevoir une chaîne ou autre.

et puis passer une chaîne vide à ctype_digit renverra vrai, tandis que null renverra faux.

enfin si ça peut éviter à quequ'un de chercher pour rien...

ps : faut pas oublié non plus le bon setlocal sinon ctype_alnum renverra faux si présence du caractère 'é'

ps2 : de toute manière à peu de choses près is_integer reste plus rapide que ctype_digit

ps3: ya pas à dire sydney bechet il savait jouer

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

04 avr. 2006, 21:41

Ce qui nous intéresse ici ce sont les fonctions de validation, pour vérifier ce qu'a entré l'utilisateur donc on travaille sur des chaînes et is_integer n'est pas vraiment approprié. Après tout, si la variable est un (int) alors on sait déjà qu'elle ne contient que des chiffres.

Ce que tu dit sur ctype_digit('') est faux (sur PHP 5.1.2, je n'ai pas pris la peine de vérifier sur les anciennes versions), en revanche le point sur ctype_digit((int) $i) est intéressant et à noter.

Invité
Invité n'ayant pas de compte PHPfrance

04 avr. 2006, 22:11

Ce qui nous intéresse ici ce sont les fonctions de validation, pour vérifier ce qu'a entré l'utilisateur donc on travaille sur des chaînes et is_integer n'est pas vraiment approprié.
si tu sous entend que tu compte juste traiter les param get et post alors je suis d'accord avec toi, tu recevras que des chaînes.
Après tout, si la variable est un (int) alors on sait déjà qu'elle ne contient que des chiffres.
je te suis pas trop...mais bon si tu le sait déja c'est sûr qu'il n'y a plus rien à vérifier :)
Ce que tu dit sur ctype_digit('') est faux (sur PHP 5.1.2, je n'ai pas pris la peine de vérifier sur les anciennes versions)
v 4.4 et 5.04.
merci pour l'info, si ça été corrigé alors tant mieux parece que ça me paraissais pas très logique comme comportement...

et puis le setlocal pour les chaîne c'est aussi important (bon c'est surtout que ça m'a fais perdre du temps lors d'un dev).

mais comme je l'ai dit plus haut le but c'était surtout de filer des précisions sur l'utilisation des ctype_xxx (à l'intérieur d'un post qui s'appel "ctype" j'ai pas pu m'en empêcher) pour éviter des prises de tête inutiles , d'autant qu'elles sont pas trop connu.

Invité
Invité n'ayant pas de compte PHPfrance

04 avr. 2006, 22:45

oupps j'ai oublié un truc.

quand tu vérifie un integer is_numeric te sert à rien vu qu'il laissera passer un float :wink: