Forum Programmation.php Fonctionnement du OR

Posté par .
Tags : aucun
0
29
juil.
2004
Bonjour,

je programme en PHP 4.

Je me suis rendu compte d'un phénomène que je trouve anormal.

Dans cette ligne de code :

if( BDD::Requete($sql_actuellement, 'actuellement') || BDD::Requete($sql_prochainement, 'prochainement') )

Je m'attend à ce que la fonction Requete() de la classe BDD soit exécuté deux fois. Si l'un des deux appel retourne TRUE, le code situé dans le if doit être exécuté.

Malheureusement pour moi, PHP4 ne fonctionne pas comme ça.

Il va exécuter la première fonction et si elle retourne TRUE, il rentre directement dans le if sans se soucier de la deuxième exécution de la fonction.

J'ai cherché sur la documentation officiel ( www.php.net ) mais rien n'est dit à ce sujet.

Avez vous une suggestion pour que quelque soit le cas, les deux appels de fonction soient traité ?

Merci.
  • # Normal

    Posté par (page perso) . Évalué à 3.

    C'est bien comme ca que ca se passe (en C, et autres aussi), c'est une optimisation. En perl d'ailleurs il est très courant de faire instruction or die par exemple, le die n'étant executé que si l'instruction n'a pas renvoyé vrai. Pour traiter les 2 appels une solution est :
    $ret = BDD::Requete($sql_actuellement, 'actuellement');
    $ret2 = BDD::Requete($sql_prochainement, 'prochainement'));
    if ($ret || $ret2) ...
    
    • [^] # Re: Normal

      Posté par . Évalué à 2.

      c'est pas une optimisation. C'est définie comme. La deuxième opérande n'est évaluée que si nécessaire.
      • [^] # Re: Normal

        Posté par . Évalué à 1.

        La deuxième opérande n'est évaluée que si nécessaire.
        Ce qui constitue une optimisation...
        • [^] # Re: Normal

          Posté par (page perso) . Évalué à 2.

          Non encore une foi ce n'est pas une optimisation, c'est le comportement de l'operande 'OU Logique'.

          Il n'y a pas d'optimisation la dedans, ni de d'implementation a definir pour chaque langage, c'est la definition du OU logique et tout le monde le comprend comme cela, que ce soit les hommes ou les machines (pour peu qu'on ai pris la peine d'en lire la definition).
          • [^] # Re: Normal

            Posté par . Évalué à 2.

            Oui, mais le OU est une opération binaire qui nécessite donc donc deux opérandes.

            Quand tu fais un +, tu évalue les deux opérandes puis tu les additionne.

            Pour le OU, tu devrais faire pareil.

            Or, comme la valeur de la première opérande peut suffir dans certain cas pour déterminer le résultat et que donc la valeur de la seconde ne sera pas déterminante, on optimise le traitement en n'évaluant pas la seconde opérande.

            Maintenant, si tu a envie de te faire taper les doigts par ton prof de math...

            Sinon, OU n'est pas une opérande dans notre context:
            http://www.linux-france.org/prj/jargonf/O/opeacrande.html(...)
          • [^] # Re: Normal

            Posté par (page perso) . Évalué à 3.

            Alors là je veux bien un lien vers la définition officielle, parcque le OU Logique est pour moi défini par sa table dé vérité, nullement par la façon dont on arrive au résultat.
          • [^] # Re: Normal

            Posté par (page perso) . Évalué à 2.

            Hum.. la "définition du OU logique".... la définition est claire et impose que chacun des opérande soit un booléen. Elle n'est pas claire lorsque chaque opérande est elle-même un calcul (notre cas).

            En l'occurrence, c'est plutôt le fait que le calcul de l'opérande droit n'est pas nécessaire à l'obtention du résultat du OU logique dans le ca où le calcul de l'opérande gauche a donné un résultat vrai.

            D'ailleurs, essaie d'écrire une fonction qui réalise la même chose qu'un OU logique (ce comportement paresseux) : tu ne pourras pas (sauf à passer une fonction et l'éxecuter conditionnellement dans la fonction) car lorsque tu passes comme opérande (enfin, là, paramètres de la fonction) tes deux calculs ils seront effectués avant d'être passés à la fonction.

            C'est donc une optimisation dans le langage.
      • [^] # Re: Normal

        Posté par (page perso) . Évalué à 2.

        " C'est définie comme. "
        bah non justement, la doc de PHP est vraiment très vague et ne précise pas ce comportement. Ils croient sans doute que celà personne n'aura l'intention de créer un compilateur ou un interpréteur PHP... en tout cas c'est trop peu documenté le langage en soit.
        • [^] # Re: Normal

          Posté par . Évalué à 1.

          C'est vrai que dans la doc c'est flou...

          cependant en php il y a deux "ou" (et deux "et") : || et or.

          si mes souvenirs sont bons avec or tous les opérandes sont évalués même si le premier est vrai.

          mais je ne sais plus où j'ai vu ça... pas dans la doc visiblement. Sans doute dans un livre.
          • [^] # Re: Normal

            Posté par (page perso) . Évalué à 3.

            oui mais non.

            [gc@meuh /tmp] echo '<? function preda() { echo "in preda\n"; return true; } function predb() { echo "in predb\n"; } if (preda() or predb()) {} ?>' > t.php
            [gc@meuh /tmp] php t.php
            in preda
            [gc@meuh /tmp] echo '<? function preda() { echo "in preda\n"; return true; } function predb() { echo "in predb\n"; } if (preda() || predb()) {} ?>' > t.php
            [gc@meuh /tmp] php t.php
            in preda
            [gc@meuh /tmp]
        • [^] # Re: Normal

          Posté par (page perso) . Évalué à 2.

          Probablement dans tous les langages, le "ou" est implémenté de manière "paresseuse" (lazy) et n'évalue la partie droite que si la partie gauche est fausse, et certains (de mémoire) ont un opérateur spécial qui n'est pas paresseux.

          Il faut bien comprendre que l'évaluation de la partie droite du "ou" logique n'est pas nécessaire au calcul de la valeur de vérité de la branche if, si la partie gauche est déjà vraie. Alors pourquoi le langage la ferait-elle ? Ce n'est ni normal ni logique. Il n'y a pas besoin de précision particulière dans la documentation de PHP pour cela.

          On s'est trop éloigné de la programmation fonctionnelle pour avoir une compréhension intuitive du phénomène ici, qui devient un "problème". On se permet d'utiliser un prédicat qui aura en outre un effet de bord et on est triste que l'effet de bord ne soit pas obtenu alors que le prédicat n'était pas nécessaire au calcul du résultat de la valeur de vérité de la branche.

          Le seul point de documentation qui pourrait être donné, c'est de savoir si c'est d'abord l'opérande gauche du "ou" ou l'opérande droite qui doit être évalué. Je me disais que j'avais vaguement souvenance que ocaml ou haskell évalue de droite à gauche mais ce n'est pas le cas pour ocaml en tous cas :

              # let va = ref true;;
              val va : bool ref = {contents = true}
              # let preda () = print_string "in preda\n"; !va = true;;
              val preda : unit -> bool = <fun>
              # let predb () = print_string "in predb\n"; !va = true;;
              val predb : unit -> bool = <fun>
              # let _ = if (preda () or predb ()) then "yo" else "flute";;
              in preda
              - : string = "yo"

          Je suis trop nul en haskell pour tester ce langage par contre...
          • [^] # Re: Normal

            Posté par . Évalué à 3.

            Pour OCaml l'ordre d'évaluation des arguments d'une fonction (et donc d'un prédicat) n'est pas précisé dans la sémantique du langage.
            Mieux encore: il change suivant que l'on soit en interprété (ocamlrun) ou en bytecode...
            • [^] # Re: Normal

              Posté par (page perso) . Évalué à 3.

              (ocamlrun est l'interpreteur de bytecode)

              Je pense que tu confonds l'ordre d'évaluation d'une fonction (là tu as tout à fait raison) avec "or" qui n'est pas une fonction mais un builtin avec un comportement particulier.

              [gc@meuh /tmp] ocamlopt t.ml && file a.out && ./a.out
              a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.4.1, dynamically linked (uses shared libs), not stripped
              preda or predb :
              in preda
              fonction avec preda predb en parametre :
              in preda
              in predb

              [gc@meuh /tmp] ocamlc t.ml && file a.out && ./a.out
              a.out: a /usr/bin/ocamlrun script text executable
              preda or predb :
              in preda
              fonction avec preda predb en parametre :
              in predb
              in preda

              Et au passage, d'ailleurs moi aussi je confondais et c'est de ça que je me souvenais vaguement quand je parlais d'un ordre inverse d'évaluation : il s'agit bien de ocaml mais du comportement en mode bytecode à l'appel de fonctions.
          • [^] # Re: Normal

            Posté par . Évalué à 1.

            >Probablement dans tous les langages, le "ou" est implémenté de manière "paresseuse"
            Non, par exemple, dans le langage Ada, il est bien précisé que l'évaluation n'est jamais paresseuse.

            De plus, dans certains langages (notamment Ada, et aussi Pascal, je crois), l'ordre d'évaluation des paramètres d'un "ou" (ou d'un "et") n'est pas nécessairement le même que celui dans lequel les paramêtres apparaissent dans le code.

            Cela signifie en particulier que, dans ces langages, par suite d'effets de bords, certains programmes peuvent s'exécuter différemment selon le compilateur employé. La faute au programmeur, qui aurait dû y faire attention lui-même.

            >Alors pourquoi le langage la ferait-elle ?

            C'est une question de standard du langage. Si la norme précise que l'évaluation est paresseuse, c'est logique, à condition toutefois que cette norme précise aussi que les arguments d'un tel "ou" sont bien évalués dans leur ordre d'apparition (si la norme spécifie qu'il y a évaluation paresseuse, mais que l'ordre d'évaluation des arguments est indéterminé, attention aux surprises!)

            En revanche, si elle précise que l'évaluation n'est jamais paresseuse, pas de problème (sauf effets de bords et évaluation désordonnée).

            Manifestement, la norme de php4 est silencieuse à ce sujet, ce qui signifie que l'on ne peut rien prévoir à l'avance (l'évaluation peut être ou non paresseuse, être ou non ordonnée, etc...) .
            Donc le comportement observé est bien L'UN des comportements possibles de ce code, mais pas le seul.

            Cela dit, à mon avis, il serait préférable que la norme précise expressément que les caractères paresseux et ordonnés des évaluations logiques ne sont pas spécifiés, cela éviterait les embrouilles.
  • # Comportement normal

    Posté par . Évalué à 2.

    C'est le comportement par défaut depuis la version 3

    http://www.php.net/manual/fr/migration.booleval.php(...)
    • [^] # Re: Comportement normal

      Posté par . Évalué à 1.

      Hello tout le monde,

      Pour ma part je ne vois pas où est les problème. Comme son nom l'indique le traitement est effectué si l'une ou l'autre des conditions est respectée. Donc si la première l'est pas besoin d'aller plus loin, on n'est pas dans le cas d'un ET.
      Dans ce cas si
      BDD::Requete($sql_actuellement, 'actuellement')
      est correcte on rentre dans le if.
      Si ce n'est pas correct on lit la deuxième condition.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.