PHP 5.3 : getopt : Paramètres en ligne de commande

7 novembre 2008cli, php, php-5.3
 Cet article a été rédigé il y a plusieurs années et peut ne plus être tout à fait à jour…

Les exemples correspondant à ce point se trouvent dans le répertoire "getopt".

Sommaire

Getopt ?

Introduction

La fonction getopt, qui existe depuis PHP 4.3, permet de récupérer dans un script PHP les paramètres qui lui ont été passés en ligne de commande.

Elle a donc son utilité en mode CLI -- par exemple, pour développement de traitements batch -- et non au niveau des sites Web en eux-mêmes.

La fonction getopt accepte deux types de paramètres :

  • Les options << courtes >>, d'une seule lettre : mon-programme.php -a -b 10 -cde
  • Les options << longues >>, de plusieurs lettres : mon-programme.php --option-longue --option=10[1]

Mais le support des options longues, en PHP <= 5.2, était limité à seulement quelques systèmes. En particulier, il n'existait pas sous Windows -- et n'était pas forcément actif sous Linux.


Nouveautés en PHP 5.3

PHP 5.3 introduit plusieurs nouvelles fonctionnalités au niveau de la fonction getopt :

  • Elle supporte à présent les options longues, en natif, sous tous OS,
  • Elle supporte à présent les options << optionnelles >>,
  • Et << = >> a été ajouté comme séparateur nom d'option / valeur.


Options courtes

Commençons par un tour des options courtes.

Une option courte est une option sur une seule lettre précédée d'un tiret ; et il est possible de << raccourcir >> l'écriture, en regroupant plusieurs options courtes et ne les préfixant que d'un seul tiret.

Dans le cas où l'on souhaite travailler avec des options courtes, il convient de fournir en premier paramètre à getopt une chaîne de caractères décrivant ceux-ci :

  • Chacune des lettres de cette chaine sera considérée comme une option attendue par le script,
  • Avec la possibilité de spécifier si le paramètre est optionnel ou non :
    • Une lettre suivie de << : >> codera pour un paramètre obligatoire,
    • Et une lettre suivie de << :: >> codera -- à partir de PHP 5.3 -- pour un paramètre optionnel.

Voici un exemple :

$options = getopt('ab:c:d::');

var_dump($options);

Ici, nous souhaitons récupérer depuis les paramètres passés en ligne de commande :

  • Une option a,
  • Des options b et c, explicitement déclarées comme obligatoires,
  • Et un option d, déclarée comme optionnelle.

Voyons ce que l'on obtient avec plusieurs appels à notre script :

$ php ./getopt/getopt-1.php -a -b10 -c=10 -d
array(4) {
  ["a"]=>
  bool(false)
  ["b"]=>
  string(2) "10"
  ["c"]=>
  string(2) "10"
  ["d"]=>
  bool(false)
}

Nous n'avons pas spécifié si l'option a devait être obligatoire ou optionnelle...
a ne sera jamais récupérée, quoi que nous passions au script : il nous fallait faire suivre a de : ou de ::, au choix.

Nous avons spécifié -b10 en paramètre. getopt a reconnu cette option et cette syntaxe, et a affecté 10 à l'option b, comme attendu.

Nous avons ensuite utilisé -c=10 :

  • En PHP 5.3, getopt reconnait = comme séparateur nom d'option / valeur, et affecte 10 à l'option c.
  • En PHP 5.2, = n'est pas admis comme séparateur, et l'option c aurait été considérée comme valant =10 !

Et enfin, nous avons spécifié l'option -d, optionnelle, sans lui fournir de valeur.
getopt la considère donc comme fausse.

Essayons maintenant de passer le paramètre optionnel :

$ php ./getopt/getopt-1.php -a -b10 -c=10 -d=glop
array(4) {
  ["a"]=>
  bool(false)
  ["b"]=>
  string(2) "10"
  ["c"]=>
  string(2) "10"
  ["d"]=>
  string(4) "glop"
}

Cette fois-ci, la valeur de d a bien été récupérée : << glop >> !

Encore une fois, notez que le séparateur = n'est accepté que depuis PHP 5.3 : ici encore, en PHP 5.2, l'option d aurait eu pour valeur =glop !

Encore un, en ne passant plus que les deux premiers paramètres :

$ php ./getopt/getopt-1.php -a -b10
array(2) {
  ["a"]=>
  bool(false)
  ["b"]=>
  string(2) "10"
}

L'option d, qui était déclarée comme optionnel et n'a pas été passée au script, n'est pas présente dans la liste des options retournées par getopt.

Par contre, on notera que c, qui n'était pas déclarée comme optionnelle, n'y est pas non plus : c'est toujours à vous de gérer les situations où vos utilisateurs ne font pas ce que vous souhaitiez !
Note : le comportement en PHP 5.2 est strictement identique, à ce niveau.

Et, cette fois, en regroupant nos options courtes :

$ php ./getopt/getopt-1.php -ab10 -c=10
array(3) {
  ["a"]=>
  bool(false)
  ["b"]=>
  string(2) "10"
  ["c"]=>
  string(2) "10"
}

Comme nous aurions pu nous y attendre, nous pouvons regrouper les options courtes ^^

Ici encore, nous avons le même comportement qu'en 5.2, pour ce qui est du regroupement des options courtes, du moins.
(J'ai déjà parlé plus haut du séparateur = non reconnu en 5.2 ; je ne reviendrai pas dessus)


Options longues

Passons à présent aux options longues : la grande nouveauté est qu'elles sont supportées, en natif, sur tous systèmes, et ne sont plus dépendantes des fonctionnalités sous-jacences de l'OS.

Plus simplement, cela signifie qu'il est possible d'utiliser des options longues avec getopt sur plate-forme Windows.

Comme exemple, je prendrai la portion de code suivante :

$options = getopt(null, array(
        'aa',
        'bb:',
        'cc:',
        'dd::',
    ));

var_dump($options);

Le premier paramètre passé à getopt est null : nous ne souhaitons pas travailler avec des options courtes.

Ensuite, nous reprenons les mêmes options que plus haut dans notre exemple d'options courtes, en doublant simplement le nom de chaque option, pour les allonger ^^
Donc :

  • Une première option aa,
  • Des options bb et cb, explicitement déclarées comme obligatoires,
  • Et un option dd, déclarée comme optionnelle.

La différence entre la déclaration des options courtes et des options longues est que, dans le premier cas, on les regroupe au sein d'une unique chaine de caractères, alors que, dans le second cas, nous utilisons une liste -- c'est plus simple pour déterminer quels sont les noms des options ^^

Premier exemple d'appel :

$ php ./getopt/getopt-2.php --aa --bb 10 --cc=10 --dd=glop
array(4) {
  ["aa"]=>
  bool(false)
  ["bb"]=>
  string(2) "10"
  ["cc"]=>
  string(2) "10"
  ["dd"]=>
  string(4) "glop"
}

Nous n'avons toujours pas spécifié si aa devait être obligatoire ou optionnelle...
Comme plus haut avec a, donc, aa ne sera jamais récupérée, quoi que nous passions au script : il nous fallait faire suivre aa de : ou de ::, au choix.

Nous avons cette fois-ci spécifié -bb 10 en paramètre. getopt a reconnu cette option et cette syntaxe, et a affecté 10 à l'option bb, comme attendu.

Nous avons ensuite utilisé --cc=10 :

  • En PHP 5.3, getopt reconnait = comme séparateur nom d'option / valeur, et affecte 10 à l'option c.
  • En PHP 5.2, j'aurais aimé tester... Mais la version de PHP 5.2 fournie par Ubuntu ne supporte pas les options longues, et renvoi un warning : -- oui, sous Linux sous non plus, les options longues ne sont pas forcément supportées ^^
$ php ./getopt/getopt-2.php --aa --bb 10 --cc=10 --dd=glop

Warning: getopt(): No support for long options in this build in /home/squale/developpement/tests/php53/getopt/getopt-2.php on line 10

Call Stack:
    0,0005      60384   1. {main}() /home/squale/developpement/tests/php53/getopt/getopt-2.php:0
    0,0005      60960   2. getopt(string(0), array(4)) /home/squale/developpement/tests/php53/getopt/getopt-2.php:10

array(0) {
}

Et enfin, nous avons spécifié l'option -dd, optionnelle, en lui fournissant une valeur, qui a été extraite avec succès : << glop >>.

Second essai, sans passer du tout l'option optionnelle dd :

$ php ./getopt/getopt-2.php --aa --bb 10 --cc=10
array(3) {
  ["aa"]=>
  bool(false)
  ["bb"]=>
  string(2) "10"
  ["cc"]=>
  string(2) "10"
}

Ici encore, si une option non-obligatoire n'est pas passée, elle ne sera pas présente dans la liste retournée par getopt : à vous de gérer ce type de situation, donc !

Et plus loin, en ne fournissant pas non plus l'option bb, qui était pourtant obligatoire :

$ php ./getopt/getopt-2.php --cc=10
array(1) {
  ["cc"]=>
  string(2) "10"
}

C'est toujours à vous de vous débrouiller !


Cela n'aura que peu d'importance pour ceux d'entre nous qui font du développement Web sans avoir de traitement batch évolués derrière, mais PHP 5.3 ajoute enfin à la fonction getopt -- et au support de la ligne de commande, donc -- les fonctionnalités dont il était difficile de se passer !

Un peu tard, peut-être : devant la faiblesse de getopt, certains Frameworks ont déjà pris sur eux de fournir des fonctionnalités poussées pour ce qui est du support des options en CLI !


Note

[1] ça y est, je maudis Dotclear et les plugins que j'ai installé, qui convertissent les doubles-tirets soit en mise en forme << barré >> soit en tirets-quadratins ^^ ; Mais heureusement, pas dans les portions de code-source !