PHP 5.3 : goto

le - Lien permanent 10 commentaires

Les exemples correspondant à ce point se trouvent dans le répertoire “goto”.

Une des nouveautés introduite par PHP 5.3, et pas toujours bien acceptée semble-t-il, est l’ajout de la directive goto.

Sommaire :


Ajout de la directive goto

Le principe est le même que dans les autres langages que vous avez déjà eu l’occasion d’utiliser :

  • Vous définissez une étiquette (un label) à un endroit dans votre code,
    • Une étiquette se définissant en utilisant son nom, suivi du symbole ‘:’.
    • Le nom de l’étiquette est soumis aux mêmes contraintes que les noms de variables, sans le $.
  • et vous utilisez, à un autre endroit, la directive goto pour sauter vers cette étiquette.

Par exemple, pour définir une étiquette nommée “c”, et y sauter :

echo '<p>a</p>';

goto c;

echo '<p>b</p>';

c:
echo '<p>c</p>';

L’affichage commencera par la première instruction echo, et l’exécution sautera ensuite vers l’étiquette c, n’exécutant pas la seconde sortie écran :

a

c

Quelle utilité pour vos programmes ?
Certains développeurs vous diront aucune…
D’autres, peut-être un brin plus modéré, admettront l’usage de goto dans quelques cas exceptionnels, typiquement pour sortir de profondes imbrications de boucles[1].


Pas de support des goto dynamiques

L’instruction goto souffre tout de même d’une certaine limitation, qui ne sera peut-être que bénéfique à la qualité du code de certaines applications PHP : il n’est pas possible de sauter vers une étiquette dont le nom serait déterminé dynamiquement, à l’exécution : le nom de l’étiquette vers laquelle l’exécution de code sautera doit être inscrit en dur dans le code PHP.

Par exemple, prenons la portion de code suivante :

echo '<p>a</p>';

$label = 'c';
goto $label; // Parse error: syntax error, unexpected T_VARIABLE, expecting T_STRING

echo '<p>b</p>';

c:
echo '<p>c</p>';

Essayer d’exécuter ce code ménera à une Parse Error : le code ne compile même pas :

not-goto-dynamic-label.png


goto et blocs

La nouvelle instruction goto permet de sauter en plein milieu de certains types de blocs ; typiquement, les blocs conditionnels if.
Par exemple, prenons le code suivant :

$a = 10;
goto label;
if ($a == 20) {
  label:
    echo 'a == 20 !';
} else {
    echo 'a != 20';
}

La sortie obtenue sera :

a == 20 !

Alors que a ne vaut définitivement pas 20 !
(Voici typiquement un très mauvais exemple d’utilisation de goto, soit dit en passant ^^ )


Par contre, vous ne pouvez pas sauter au milieu d’un bloc correspondant à une instruction de boucle (for, while, …), ni au milieu d’un bloc switch.
Par exemple, en utilisant le code suivant :

goto label2;
for ($i=0 ; $i<10 ; $i++) {
  label2:
    echo $i . "\n";
}

Vous obtiendrez une Fatal Error :

not-goto-into-loop.png


Pas de support de break vers une étiquette

Enfin, l’ajout du support de goto et de la notion d’étiquettes aurait pu amener à penser que les instructions break et continue auraient pu être modifiées, de manière à être capables de sauter vers une étiquette, ce qui est tout de même plus lisible — et surtout, plus maintenable, que de les utiliser pour sortir d’un nombre de boucles, ce qui casse à chaque fois que l’on modifie nos imbrications…
(Ceux qui ont déjà développé en Perl verront probablement de quoi je parle, à ce sujet)

Mais cette fonctionnalité n’a pas été introduite :-(

Par exemple, voici break utilisée pour sortir d’une double imbrication :

for ($i=0 ; $i<5 ; $i++) {
    for ($j=0 ; $j<5 ; $j++) {
        for ($k=0 ; $k<5 ; $k++) {
            echo "$i ; $j ; $k \n";
            if ($k == 2) {
                echo "break 2\n";
                break 2;
            }
        }
    }
}

Est-ce que ce code ne serait pas plus lisible écrit de la manière suivante :

for ($i=0 ; $i<5 ; $i++) {
  label:
    for ($j=0 ; $j<5 ; $j++) {
        for ($k=0 ; $k<5 ; $k++) {
            echo "$i ; $j ; $k \n";
            if ($k == 2) {
                echo "break 'label'\n";
                break 'label';  // ne break que de un niveau => ne fonctionne pas
                    // et sans les quotes :
                    // Notice: Use of undefined constant label - assumed 'label'
            }
        }
    }
}

(La sortie de cet exemple trop longue pour être reproduite ici)

Mais ce code ne fonctionne pas :

  • En utilisant « break label; », on obtient une notice :

not-break-label.png

  • Et en mettant nous-même les quotes (en utilisant « break 'label'; », donc), nous ne sortons que d’un niveau de la boucle, et pas deux comme nous l’aurions souhaité.

Peut-être pour une prochaine version ?


Note

[1] Encore que, en PHP, nous avons la possibilité d’utiliser l’instruction break en lui précisant de combien de niveaux de profondeur elle doit sortir…

Vous avez apprécié cet article ? Faites le savoir !

Commentaires

1. Par Laurentj le 2008-10-28 10:06
Laurentj

Franchement, cette instruction goto, c'est un gros retour en arrière vis à vis des bonnes pratiques en programmation. C'est vraiment du grand n'importe quoi. Je ne comprend pas qu'ils aient introduis ce truc. Ils ne doivent pas être conscient des ravages que peut faire cette instruction sur la maintenance et l'évolution du code d'un programme. Et j'en sais quelque chose, j'ai du bossé il y a 10 ans sur des évolutions à faire sur des programmes en cobol qui utilisaient des goto dans tout les sens : code spaghetti INMAINTENABLE. Une horreur sans nom.

D'ailleurs, il ne faudrait même pas en parler de ce truc immonde. Tu devrais effacer ce post, pour qu'il y ait le moins de monde possible au courant de cette ignominie :-) (au passage, merci pour cette série sur les nouveautés de PHP 5.3 ;-) )

2. Par Laurentj le 2008-10-28 10:17
Laurentj

Ah, oui, autre chose.

>Pas de support des goto dynamiques

HEUREUSEMENT ! suivre le parcours d'un programme où il y a des goto, c'est déjà très pénible à lire, alors si en plus on ne sait pas où on va !!! En effet, il faudrait aussi suivre ce qui change dans la variable utilisée, ce qui n'est pas toujours faisable ou prédictible, et rendrait du coup le code totalement illisible. Bonjour pour débugger !!!

>goto et blocs

Ton exemple montre clairement l'abomination de l'instruction goto : on peut s'en fiche royalement des conditions ou autre. Ce qui peut provoquer des comportements inattendu ou franchement dur à debugger. Là, ça va, tu as 3 lignes de code, mais imagine que le goto soit dans un autre fichier php parmis des dizaines, et donc avec des centaines de lignes de code qui séparent le goto de l'étiquette.

Ça fait froid dans le dos quand même, pour l'avenir de la qualité du code des prochains softs en PHP, si les développeurs (bien souvent amateurs dans le monde PHP) utilisent goto de manière irréfléchi...

>Pas de support de break vers une étiquette

heureusement (bis) ! Sinon ça n'aurait aucun sens, car ça voudrait dire deux instructions, goto et break, qui font la même chose. Quel intérêt alors d'avoir un goto ? (déjà que cet intérêt est quasi nul)

3. Par Romain F. le 2008-10-28 12:07
Romain F.

Le goto, c'est pour ceux qui ne savent pas utiliser les fonctions et les classes proprement ?

Perdon pour le troll, mais sérieusement, si je vois un collaborateur faire des goto, je l'assassine ! C'est un retour en arrière que je ne comprend pas !

4. Par Pascal MARTIN le 2008-10-28 20:31
Pascal MARTIN

Et bien, moi qui m'attendais à des réaction hostiles, je ne suis pas déçu ^^

Laurentj >

  • Je ne supprimerai pas :p
  • Comme tu dis, ça risque d'être l'enfer en maintenance... si c'est utilisé ; et j'espère de tout cœur que ça ne le sera que peu (et judicieusement uniquement, ce qui veut dire *peu*), en particulier pour des applications "pro"
  • Merci à toi pour la pub sur ton blog ;-)
  • Pour le break dynamique : 100% d'accord ; même chose pour l'exemple du goto au milieu du bloc if (pas choisi par hasard, celui-là :-D )
  • Par contre, pour l'absence de break + label... Boah, ça n'aurait pas été la première fonctionnalité redondante de PHP ^^ Mais un break + label aurait fait du bien, à mon sens : il aurait eu le mérite de rendre lisible les "break 3;" pour lesquels on ne sait jamais à quoi correspond le "3" :-(
Romain F > sans aller jusqu'à l'assassinat, je demanderai à ce que l'utilisation d'un goto soit... disons... justifiée ^^
5. Par brice le 2008-10-28 21:19
brice

Effectivement, si un développeur use du goto, il doit aussi abusé du break donc il aurait été plus logique de le labelliser :)

Il serait intéressant, si tu les as, de retrouver les mails ou RFC qui ont justifiés des incorporations tels que celles-ci. Je vais investiguer.

En attendant, on peut aussi relire cet article de Donald Knuth sur le "go to" : http://pplab.snu.ac.kr/courses/adv_...

6. Par Pascal MARTIN le 2008-10-28 21:52
Pascal MARTIN

Pour ce qui est de goto, je n'ai pas trouvé de RFC.

Par contre, en fouillant dans les archives de internals, le plus vieux que je trouve est un post de Sara Golemon le 18 juillet 2004, où elle poste un patch ajoutant le support de goto à PHP -- patch qu'elle avait écrit pour s'entrainer à bosser avec le Zend Engine, et ne pensait pas diffuser.

Cf http://markmail.org/search/?q=%22GOTO+operator%22+internals+php+sara+golemon+order%3Adate-forward pour les échanges ^^

Un bug-report à ce sujet, aussi, pour lequel les échanges commencent par un We won't implement goto and or labels, et finissent par un (Limited) goto was added some time ago to HEAD (PHP 6). : http://bugs.php.net/bug.php?id=29287

Et après, que ce soit en 2004 ou en 2008, tu peux tomber sur un paquet de blog-posts ^^
Quelques exemples :

Enfin, je sens qu'on va en entendre parler pendant longtemps, de ces quatre (trois ? ) lettres ^^
(Et sur certains aspects -- dont celui-ci -- j'ai hâte de faire ma première revue de code sur une application PHP 5.3, voir si ce genre de choses auront été utilisées, et comment...)
7. Par quode le 2008-11-30 04:14
quode

L'instruction goto a son utilité tout de même. Son usage restera à mon avis très anecdotique.

8. Par Pascal MARTIN le 2008-11-30 22:42
Pascal MARTIN

On entend tellement depuis quelques années que "goto c'est mal" que oui, probablement, son usage restera anecdotique ; s'il est réservé aux cas où il apporte réellement un plus, notamment en termes de simplicité du code, et de facilité de maintenance, pourquoi pas ?

9. Par thomas le 2009-02-25 20:50
thomas

Cela fait longtemps que j'attendais le "goto" en PHP, tout comme le "break n" me manque dans d'autres langages.
A ceux qui diabolisent l'ami "goto", n'oubliez pas que le monde de la programmation est vaste, et que, si sur l'intégralité de vos projets, vous n'aurez peut-être jamais de bonnes raisons de l'utiliser, il existe aussi des cas où "goto" augmente la lisibilité et la qualité du code. Je vous l'accorde, il s'agit de cas assez particuliers, et non-triviaux.

Ceci dit, je vous rejoins sur un point, il sera très probablement mal utilisé par des codeurs débutants. Mais bon, les dits codeurs utilisant déjà mal les objets, les tableaux associatifs, les sessions et tout le reste, on verra pas bien la différence... C'est pas en pensant aux mauvais qu'il faut faire évoluer le langage.

10. Par Arnaud Lemercier le 2012-04-18 10:45
Arnaud Lemercier

Pour ma part, j'ai trouvé une utilité pas trop saledans un projet qui n'utilise pas de gestionnaire de formulaire (Zend_Form).

Dans mon action de controller, j'ai des tas de tests à la suite pour valider les données du formulaire. En cas d'erreur du premier tests, je n'ai pas besoin de passer les autres donc un goto response et je saute directement au retour json de mon action.

Si ça peut décomplexer ceux qui voulaient utiliser goto ^^

Ce post n'est pas ouvert aux nouveaux commentaires (probablement parce qu'il a été publié il y a longtemps).