Les petites choses marrantes en PHP: tester une string

Dans notre précédent article, nous avions vu plusieurs astuces pour simplifier nos conditions, en utilisant quelques règles de typage. Toutefois, il ne faut pas croire que tout soit aussi systématique. Il existe des pièges qu’il s’agit d’éviter.

L’occasion idéale pour un nouvel article de notre série Les petites choses marrantes en PHP, consacrées aux petites choses marrantes en PHP, avec quelques exemples de petites choses marrantes en matière de test sur des string.

Mais attention, que les choses soient bien claires: comme tous les articles de cette série, il ne s’agit pas de troll! Juste de faire gaffe…

Comment tester une string vide?

Vous voulez écrire une condition qui ne laisse passer que les string qui ne sont pas vides. Simple, me diriez-vous? Pas si sûr…

Test sur la variable

Commençons avec une écriture dépouillée: on teste juste une variable dans une condition.

1
2
3
if($str){
    ...
}

Ma string vaut ""

Que va-t-il se passer? Notre variable va être castée dynamiquement en booléen. Une string vide castée en booléen va effectivement retourner false. Le test est correct.

1
2
3
4
5
$str = '';

if($str){
    //ok, je n'entre pas dans la condition avec une string vide
}

Ma string vaut "0"

Nous sommes d’accord qu’une string équivalant à "0" ne peut pas être considérée comme vide. Toutefois, en PHP, caster une string "0" en booléen va retourner false. Eh oui… (même chose avec la fonction empty). Autrement dit, on n’entre pas dans la condition alors que la string n’est pas vide. Le test n’est pas correct.

1
2
3
4
5
$str = '0';

if($str){
    //oups, je n'entre pas dans la condition alors que ma string n'est pas vide
}

Marrant, non?

Comparaison stricte

On améliore notre test en précisant qu’on veut exclure spécifiquement les string vides.

1
2
3
if($str !== ''){
    ...
}

Ma string vaut "0"

Du coup, le "0" n’est plus considéré comme une string vide. Cette fois-ci, le test est correct.

1
2
3
4
5
$str = '0';

if($str !== ''){
    //ok, j'entre dans la condition
}

Ma string vaut null

Il existe malgré tout encore un piège. Tout va dépendre de la question suivante: voulez-vous accepter d’autres scalaires équivalents à false qui soient d’un autre type que string (false, null, 0, "")? En effet, si on teste la variable avec une comparaison stricte, on autorise d’autres types à rentrer dans la condition. Par exemple, null n’est pas strictement égale à "". Donc, on entre dans la condition. Le test n’est pas correct.

1
2
3
4
5
$str = null;

if($str !== ''){
    //oups, j'entre dans la condition alors que ma valeur vaut null
}

Marrant, non?

Comparaison laxiste

Seule la comparaison laxiste permet ici d’accepter les string "0", tout en refusant les string vides ainsi que les scalaires ayant une valeur équivalente à false.

1
2
3
if($str != ''){
    ...
}

Ma string vaut null

Du coup, null ne pose plus de problème. Le test redevient correct.

1
2
3
4
5
$str = null;

if($str != ''){
    //ok, je n'entre pas dans la condition
}

Ma string vaut array

Il reste malgré tout encore un piège. :) Si notre variable vaut un array (ou potentiellement un objet implémentant __toString), la conversion se fait du tableau vers la string. Or, caster un tableau en string retourne toujours la string « Array » (avec heureusement une notice depuis PHP 5.4, mais attention toutefois que cette notice ne se déclenche évidemment pas lors d’une comparaison laxiste). Dommage, on aurait préféré une string vide. Le test n’est donc pas correct.

1
2
3
4
5
$str = array();

if($str != ''){
    //oups,j'entre dans la condition
}

Marrant, non?

Comparaison stricte et test sur le type

La seule façon de s’assurer qu’aucun cas ne pose problème réside dans le test du type de la variable suivi par une comparaison stricte. Le test devient enfin correct.

1
2
3
if(is_string($str) && $str !== ''){
    ...
}

Au final, la solution n’est pas très intuitive et l’écriture de la condition n’est pas très claire. On se retrouve à l’exacte opposé de ce qui était préconisé dans l’article sur la simplification des conditions. Bien sûr, il s’agit d’adapter son test à chaque cas. Tous les contextes d’exécution n’ont pas forcément besoin d’autant de mesures de sécurité.

Comment tester une string non-vide?

Deuxième condition: vous voulez vous assurer d’avoir une string équivalente à "abc". L’enfance de l’art, me diriez-vous? Pas si sûr…

Il existe en effet un piège (juste un seul cette fois) : l’utilisation d’une comparaison laxiste.

1
2
3
if($str == 'abc'){
    ...
}

En effet, si notre variable vaut true, le cast se fera vers le booléen. Une string non vide équivalant à true, vous entrez dans la condition.

1
2
3
4
5
$str = true;

if($str == 'abc'){
    //oups, j'entre dans la condition
}

Marrant, non?

Conclusion

Le principal problème réside dans l’inconnue du typage de la valeur testée. La précédence des types ainsi que certaines conversions particulières peuvent créer des effets non désirés. Les conversions entre types ne sont pas toujours évidentes. La documentation de PHP propose notamment un tableau de comparaison des types qu’il est intéressant de relire régulièrement. Il convient donc de rester toujours prudent si le code n’est pas correctement sécurisé.

Une réflexion au sujet de « Les petites choses marrantes en PHP: tester une string »

  1. Ah le bon vieux typage dynamique. Simple en apparence ^^
    Ca me rappelle un code que j’ai débuggé cette semaine qui se comportait mal, car un string vide c’était glissé a la place d’un tableau. Et il faut savoir qu’un count() sur une string vide … Ca ne vaut pas 0 !

    php > var_dump(count( »));
    int(1)

Répondre à bux Annuler la réponse.

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>