Fonctions silencieuses (quiet evaluation)

ViPHP
ViPHP | 4674 Messages

11 déc. 2008, 20:19

Hey :),

J'aurais besoin d'utiliser des fonctions silencieuses (ou quiet evaluation selon la terminologie PHP), mais je ne sais pas comment faire ça. Je m'explique.

Le seul exemple de fonction silencieuse que je connaisse est la fonction assert() : si la configuration du php.ini le permet, la fonction s'exécute, sinon elle ne s'exécute pas.
J'aurais besoin d'avoir le même comportement. Je me suis donc pencher sur le code source pour comment ça se passait. J'ai regardé dans php-x.x.x/ext/standard/assert.c, à la ligne 138 on trouve la déclaration de la fonction et à la ligne 145, dans son corps :

Code : Tout sélectionner

if (! ASSERTG(active)) { RETURN_TRUE; }
Je vais donc voir sur la macro ASSERTG (ligne 38 à 42 du même fichier) et on voit qu'on est renvoyé sur une structure :

Code : Tout sélectionner

#ifdef ZTS #define ASSERTG(v) TSRMG(assert_globals_id, zend_assert_globals *, v) #else #define ASSERTG(v) (assert_globals.v) #endif
J'ai encore cherché (je passe les détails), et cette structure est remplie via le fichier php.ini, à travers le module global de Zend, comme on pouvait s'en douter. Mais à aucun moment un mécanisme particulier n'est appelé, ne serait-ce qu'un petit commentaire qui dit qu'on aurait pu utiliser autre chose etc.

Donc rien n'a l'air prévu dans le code PHP pour ça. On ne peut pas détourner l'évaluation d'une fonction (via un callback ou un truc du genre).

On pourrait faire par contre :
function_exist('my_toto') and my_toto(arg1, …, argn);
mais c'est trop long à écrire, je ne veux pas ça.

Dernière solution, mais connue pour être sale : l'utilisation de l'extinction d'erreur via l'arobase (@). On aurait alors :
@my_toto(arg1, …, argn);
C'est une solution qui me sied, mais c'est un peu … sale non ? Ça ne me dérangerait pas d'utiliser cette technique mais il faut (sa)voir si ça n'embête pas trop PHP. Normalement, on ne devrait pas avoir de ralentissement.

Pourquoi je veux faire ça ?
Imaginez un système de tests où l'on écrirait les tests en PHP, et pas via un langage d'assertion en commentaire. Les tests seront toujours écris mais seulement exécutés si et seulement si le paquetage de tests est présent, sinon rien ne se passe. L'utilisation de l'extinction d'erreur me semble adaptée même si c'est un moyen détourné.

Je ne vois pas d'autres façons de faire, et vous ?

Un autre avantage de la fonction assert() et que le code à tester est passé sous forme de chaîne de caractères, donc il n'y a pas d'évaluation du code. On pourrait simuler le même comportement, mais ça va être galère pour retrouver les données (variables, constantes etc.) dans le bon contexte.
Et oui, il existe assert_options() qui permet de détourner/rediriger les assertions (un simple callback dynamique), mais la fonction assert() — même si elle a des avantages — reste trop limitée.

Autre précision après relecture : quand je dis que le code n'est pas évalué, je parle du code passé en argument, car dans tous les cas, la fonction assert() est appelée, mais on regarde si on sort directement ou si on effectue le travail. Pour l'arobase, ce serait pareil : la fonction est appelée et exécutée si elle existe, sinon rien.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

ViPHP
ViPHP | 4674 Messages

15 déc. 2008, 18:24

Ce n'est pas compréhensible ou personne n'a d'idées ?
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Mammouth du PHP | 1668 Messages

15 déc. 2008, 21:25

Si mais les macro en PHP n'éxistent pas, faut voir si on peut pas étendre APC ?
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

ViPHP
ViPHP | 4674 Messages

15 déc. 2008, 22:22

Je ne parle pas de macro. C'est ce qu'utilise assert() pour fonctionner au niveau de C, mais je parle de PHP. J'ai cherché à imiter le fonctionnement de cette fonction sans réussite. Je demande donc s'il n'existe pas une astuce.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

ViPHP
ViPHP | 3607 Messages

16 déc. 2008, 11:36

Et c'est peut-être bête et pas très performant, mais un truc du style
<?php
function F($function,$arg=null){

    if(function_exist($function){
        exec($function.'('.($arg!==null ? $arg : '').')');
        // ou un truc genre
        $$function($arg);
        // mais j'ai pas testé si ça marche... ;)
    }
}

Mammouth du PHP | 1668 Messages

16 déc. 2008, 13:15

Si non, il faudrait étendre l'APC pour pouvoir, avec un syntaxe de commentaire faire comme les macros C avec plusieurs niveaux, exemple :
#declare_macro:/*#quiet_evalutation#*/ as "function_exist('my_toto') and my_toto(arg1, …, argn);"

// Du code, puis à un moment...
/*#quiet_evalutation#*/
La déclaration est définie, le commentaire est remplacé, si non, rien, je pensais à l'APC pour sa mise en cache d'OPCode...
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

ViPHP
ViPHP | 5924 Messages

16 déc. 2008, 13:36

HyWaN, regarde du côté de runkit peut être…

ViPHP
ViPHP | 4674 Messages

16 déc. 2008, 18:16

J'ai déjà pensé au Runkit, mais il ne fait pas parti de la version standard de PHP, donc je l'écarte.

Si je dois utiliser APC, autant me faire mon propre fonctionnement, mais c'est un peu moche je trouve.

Et pour Jojolapine, exec() n'est pas la bonne fonction :P, mais je comprends ton idée. On s'écarte, mais je gardais cette idée sous le coude.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

ViPHP
ViPHP | 2287 Messages

16 déc. 2008, 19:39

Je l'aurais fait comme ça, personnellement je ne pense pas que ça vaille vraiment le coup de chercher mieux :
define('FONCTION_ACTIVEE',true);

// ...

function mafonction(){
  if(!defined('FONCTION_ACTIVEE') || !FONCTION_ACTIVEE) return null;

  // Faire quelquechose d'utile ici
  $useful_stuff='ok';
  return $useful_stuff;
}
Ici on utilise donc une constante définie dans le code pour faire la bascule. Si tu tiens à avoir quelquechose d'externe, peut-être utiliser une variable d'environnement (définissable par exemple dans un .htaccess) ?
if(!@work()){ Nespresso(); } else { what(); }
______________________________

ViPHP
ViPHP | 4674 Messages

16 déc. 2008, 19:45

Pas bête, mais j'aimerais plus précisément ce comportement : si ma fonction existe (est déclarée) alors on l'exécute, sinon, pas d'erreur. D'où l'utilisation de l'arobase.
Avec ta solution, on repousse le problème dans la fonction et l'utilisateur doit modifier une constante. Alors qu'avec ma solution, ça dépend du contexte/environnement dans lequel on exécute le code.

Je ne pense pas que ce soit possible (sauf avec l'@). Mais sinon, j'ai une autre solution de rechange (totalement différente) mais un peu plus lourde. Donc je demande si jamais ;-).
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

ViPHP
ViPHP | 2287 Messages

16 déc. 2008, 19:54

Alors qu'avec ma solution, ça dépend du contexte/environnement dans lequel on exécute le code.
D'où ma proposition suivante de remplacer la constante par une variable d'environnement qui jouerait le même rôle et permettrait d'avoir deux comportements différents pour un code PHP identique (la bascule se faisant de manière externe).

Pour moi, le fait que ce soit écrit explicitement sous forme conditionnelle dans la fonction est un avantage : j'aime bien que le développeur puisse comprendre ce que fait le code et comment il le fait sans ambiguïté juste en le lisant.

Mais pourquoi as-tu ce besoin précis au fait ? :-)
if(!@work()){ Nespresso(); } else { what(); }
______________________________

ViPHP
ViPHP | 5924 Messages

16 déc. 2008, 20:56

Tu encapsules l'appel du test dans une fonction/classe qui doit se charger de l'évaluation…

ViPHP
ViPHP | 4674 Messages

16 déc. 2008, 22:21

Oui Sékil', mais il faut le minimum de code possible. J'évite d'écrire quelque chose de verbeux, ce n'est pas pour rajouter du code :).

Pour répondre à Calimero, c'est pour des assertions pertinentes en PHP. Un projet universitaire que je mène actuellement.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

ViPHP
ViPHP | 5924 Messages

17 déc. 2008, 01:21

Oui Sékil', mais il faut le minimum de code possible. J'évite d'écrire quelque chose de verbeux, ce n'est pas pour rajouter du code :).
Il faut aussi être réaliste. Si tu veux une solution acceptable, il faut faire des concessions…

ViPHP
ViPHP | 2287 Messages

17 déc. 2008, 12:35

Elle ne te tente toujours pas ma variable d'environnement ? :cry:

A la base j'ai proposé une constante car c'est une façon simple et élégante de réaliser cela en C. Si on bossait en C, la seule alternative que je peux imaginer serait de définir une macro préprocesseur, qui à ma connaissance n'a pas d'équivalent en php.

Si tu veux vraiment aller au moins verbeux (sans trop de prise de tête, cad sans aller jusqu'à envisager un patch php), je ne vois pas mieux que l'arobase.
if(!@work()){ Nespresso(); } else { what(); }
______________________________