OVH Cloud OVH Cloud

Question de philosophie

39 réponses
Avatar
Alexandre
Bonjour,

je fais appel au grands experts du PHP.

Vous vous souvenez quand le register_global faisait des siennes. Pour un
grand nombre de developpeurs il a fallu reprendre le code notamment pour les
formulaire et changer:
$toto (issu du champs de formulaire ... name="toto">)
en
$_POST['toto'].

Pour ma part, je me suis dit qu'il etait hors de question de reprendre des
pages et des pages de codes faites par des predecesseurs ou moi meme.
J'ai donc cree ca:
if(isset($_POST)) {
foreach($_POST as $key=>$val) {
//echo $key.'=>'.$val.'<p>';
$$key = $val;
}
}

Que je mettais en haut de toutes mes pages. Et ca donctionne tres bien.

Puis je me suis dit que je pouvais faire la meme chose pour une requete
SELECT. Imaginons qu'une table contienne 70 champs et que vous souhaitez
tout afficher (les 70 champs).
J'ai donc fait ceci:

$requete = "SELECT * FROM gest_parc";
$resultat = mysql_query($requete);

while($row = mysql_fetch_array($resultat,MYSQL_ASSOC)){

foreach($row as $key=>$val) {
echo $key.'=>'.$val.'<p>';
$$key = $val;
}
}

Ce qui m'evite de faire:
while ($row=mysql_fetch_object($resultat)){
$id = $row->id;
$nom = $row->nom;
.
.
.
.
}

ou un fetch_array ou encoe un mysql_result...

Tout ceci fonctionne a merveille. MAintenant la question que je me pose
c'est que je n'ai jamais vu ce genre de code sur le net ni meme dans les
applis qu'on trouve en open-source.

Je me demandais alors si j'adoptais une bonne methode, si je n'allais pas a
l'encontre de l'efficacite ou d'un certain "bon procede".

Merci d'avance

Alex

9 réponses

1 2 3 4
Avatar
__marc.quinton__
Nadine St-Amand wrote:

La copie de donnees devient surement negigeable comparativement.


pour ma part, la recopie de variable c'est pas bonne, meme si
les performances sont 1/3 moins bonnes qu'avec une variable
simple. En effet ces recopies :

* sont sujetes a erreurs,
* diminuent la lisibilité pour celui qui est vraiment habitué
a la lecture de code php. C'est tout de meme un langage particulierement
facile a lire.



pour finir, petit test rapide qui ne porte que sur l'acces
a une variable directement ou via indirection (hash) :


# php -q variable-acces.php
boucle vide = 0.062735080718994
variable ordinaire = 0.036863088607788
variable indexée = 0.096745014190674


voici le code :

<?php

function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}

# -----------------------------------------------------------------------------------
$start = microtime_float();
# boucle vide
for($i=0; $i<100000 ; $i++){
}

echo "boucle vide = " . (microtime_float() - $start) . "n";

# -----------------------------------------------------------------------------------
$start = microtime_float();
# incrémentation sur une variable ordinaire
for($i=0; $i<100000 ; $i++){
$i++;
}
echo "variable ordinaire = " . (microtime_float() - $start) . "n";


# -----------------------------------------------------------------------------------
$start = microtime_float();
$list = array( 'i' => 0);
# incrémentation sur une variable de type hash
for($i=0; $i<100000 ; $i++){
$list['i']++;
}
echo "variable indexée = " . (microtime_float() - $start) . "n";



?>

Avatar
loufoque
PHP se débrouille pour ne pas copier systématiquement les données.
On appelle ça le "lazy copy".

Et ça, ça modifie ton équation ?
Avatar
John Gallet
Bonjour,

pour ma part, la recopie de variable c'est pas bonne, meme si
les performances sont 1/3 moins bonnes qu'avec une variable
simple.
Pourquoi même si ? C'est une circonstance aggravante non ?


# php -q variable-acces.php
boucle vide = 0.062735080718994
variable ordinaire = 0.036863088607788
variable indexée = 0.096745014190674
Je rappelle au passage que 1) unix n'est pas un OS temps réel, 2) une

valeur statistique commence à 400 itérations. Accessoirement, comparons
ce qui est comparable.

for($i=0; $i<100000 ; $i++){
$i++;
}


Oui mais non, incrémentons $j à l'intérieur, là on change complètement
la donne.
J'ai passé 5 minutes sur ton script qui devient ceci :
------------------------------------
<?php
set_time_limit(0);
function microtime_float()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
define('NBTST',500);
define('NBLOOP',100000);

$bv_m=0; $b1_m=0; $b2_m=0; $bi_m=0;
for($cpt=0;$cpt<NBTST; $cpt++)
{
# ------------------------------------------
$start = microtime_float();
# boucle vide
for($i=0; $i<NBLOOP ; $i++){
}
$bv=microtime_float() - $start;
$bv_m+=$bv;
# ------------------------------------------
$start = microtime_float();
# incrntation sur une variable ordinaire
for($i=0; $i<NBLOOP ; $i++){
$i++;
}
$b1=microtime_float() - $start;
$b1_m+=$b1;
# ---------------------------------------------
$start = microtime_float();
# incrntation sur une variable ordinaire
for($i=0; $i<NBLOOP ; $i++){
$j++;
}
$b2=microtime_float() - $start;
$b2_m+=$b2;
# ----------------------------------------------
$start = microtime_float();
$list = array( 'i' => 0);
# incrementation sur une variable de type hash
for($i=0; $i<NBLOOP ; $i++){
$list['i']++;
}
$bi=microtime_float() - $start;
$bi_m+=$bi;
}// end general loop

echo "raw : n$bv_mn$b1_mn$b2_mn$bi_mn";

$bv_m/=NBTST;
$b1_m/=NBTST;
$b2_m/=NBTST;
$bi_m/=NBTST;

echo "MOYENNE : n$bv_mn$b1_mn$b2_mn$bi_mn";
// reelle difference de perfs sur 1 million d'occurences
// entre $j++ et $toto['i']++
$delta = $bi_m-$b2_m;
echo "DELTA sur 1million : $deltan";

?>

------------------------------------
Résultat :
[linux:]/home/users/jgallet
Yes Master ?>php -q toto.php
raw :
27.076412439346
17.492549180984
34.978538036346
43.474288225174
MOYENNE :
0.054152824878693
0.034985098361969
0.069957076072693
0.086948576450348
DELTA sur 1million : 0.016991500377655

(17 ms)

On remarque bien qu'il y a une sacrée différence de temps dans le cas où
on incrémente la même variable que celle de la boucle en temps brut.
Normal il y a deux fois moins d'itérations dans la boucle for. Et il
faut bien retirer le temps "à vide" pour comparer $j++ et
$toto['nom']++;

Ensuite, en exécutant 10 fois ce même script, j'ai un delta compris
entre 21ms et 12ms (quand je disais qu'unix n'est pas temps réel...).

Allez, osons même 25 millisecondes de delta sur 1 million de "++" ça
fait pas besef gagné au bout du compte dans un programme de 50000
lignes...

Bref, si je suis le premier à gueuler contre les recopies inutiles et
les couches (objet ou non) qui ne servent à rien, c'est pas à cause de
la différence entre une variable "simple" et une variable mise dans une
hash table.

a++;
JG

Avatar
Marc
Bonjour,


pour ma part, la recopie de variable c'est pas bonne, meme si
les performances sont 1/3 moins bonnes qu'avec une variable
simple.


Pourquoi même si ? C'est une circonstance aggravante non ?




faire une recopie prendra certainement quelque micro-secondes,
c'est a dire environ le temps d'une lecture et d'une affectation.
On peu imaginer que lecture et ecriture prendre environ le meme
temps.


Si l'utilisation apres la recopie n'est que de quelque unités
il s'agit bien d'une perte d'energie.

D'autre part, c'est au moteur php de prendre en compte ces optimisations
d'acces aux variables. Ce n'est pas de la responsabilité du programmeur,
autant programmer en C, ou en assembleur. Si php dispose des tableaux
indexés par chaine, ce n'est pas pour les utiliser a 50%.

Bref, si je suis le premier à gueuler contre les recopies inutiles et
les couches (objet ou non) qui ne servent à rien, c'est pas à cause de
la différence entre une variable "simple" et une variable mise dans une
hash table.


je ne crois pas que les couches objets ligth (legeres donc) soient
inutiles et inefficasses. Il m'arrive parfois d'implementer la notion
de cache d'une facon tres efficasse en techno objet. Je ne sais
pas s'il est aussi facile de le realiser en procedural.

L'inconveniant de l'objet bien fait, c'est qu'il y aura beaucoup
d'appel a des methodes legeres, cela fait beaucoup d'appel de
fonction et cela a un cout. Les methodes kilometriques au contraire
des petites methodes (que je qualifie d'atomique ou moleculaires)
ne sont que peu modifiables et pas du tout surchargeables.

Il ne faut pas croire en objet et en procedural, on execute sensiblement
la meme quantité de code enfin dans les conceptions simples. Et a quoi
bon, meme si c'est le double de code (principalement des appels
de methodes et instantiation), cela ne fait que le double. Le
code actif, celui qui realise les actions sera globalement le meme.

Il existe des applications qui se prettent tres tres bien a la
conception objet. Tout ce qui concerne la generation de graphisme
avecc GD par exemple. La gestion des formulaires avec les différents
objets html. Un site Web peut etre considéré comme un ensemble de
page assemblant des formulaires consitués d'objets html. Rien
que dans cette derniere phrase, 5 classes d'objets peuvent
etre produits naturellement.


Avatar
bruno modulix
Nadine St-Amand wrote:
Enfin, ça ne rajoute toujours pas à la lisibilité du code.


La syntaxe est extremement alourdie avec les $_POST et les $_GET
obligatoires, du fait que les acces dans les tableaux ne se
dereferencent pas dans les chaines comme les variables simples.

Un exemple naif pour illustrer :

$sql = "insert into matable(var1, var2) values('$test1','$test2')";

est beaucoup plus lisible donc maintenable que

$sql = 'insert into matable(var1, var2) values(''.
$_POST[test1].'',''.$_POST[test2].'')';


1/ c'est $_POST['test1'], pas $_POST[test1]

2/ la syntaxe :
$sql = "insert into matable(var1) values({$my_array['test1']})";
est parfaitement légale. C'est certes un peu moins limpide que ton
premier exemple, mais tout de même nettement plus que le second...

3/ par contre, passer directement les saisies utilisateur dans une
requête, c'est ouvrir grand la porte aux pirates de tout poil.

4/ donc, de toutes façons, il faudra *dans ce cas* passer par des
variables intermédiaires.

Bref, faudra trouver un meilleur exemple pour me convaincre !-)

NB : Je parlais d'éviter les recopie *inutiles* qui consomment
(inutilement, donc...) des ressources sans autre effet que de rendre le
code moins explicite. Pas de faire l'impasse sur les traitements
nécessaires...

--
bruno desthuilliers
ruby -e "print ''.split('@').collect{|p|
p.split('.').collect{|w| w.reverse}.join('.')}.join('@')"


Avatar
Olivier Miakinen

$sql = "insert into matable(var1, var2) values('$test1','$test2')";

est beaucoup plus lisible donc maintenable que

$sql = 'insert into matable(var1, var2) values(''.
$_POST[test1].'',''.$_POST[test2].'')';


1/ c'est $_POST['test1'], pas $_POST[test1]


Oui.


2/ la syntaxe :
$sql = "insert into matable(var1) values({$my_array['test1']})";
est parfaitement légale. C'est certes un peu moins limpide que ton
premier exemple, mais tout de même nettement plus que le second...


Dans ce cas, la syntaxe :
$sql = "insert into matable(var1) values($my_array[test1])";
est tout aussi légale, et encore plus limpide.

3/ par contre, passer directement les saisies utilisateur dans une
requête, c'est ouvrir grand la porte aux pirates de tout poil.


Oui.

4/ donc, de toutes façons, il faudra *dans ce cas* passer par des
variables intermédiaires.


Oui.

Bref, faudra trouver un meilleur exemple pour me convaincre !-)

NB : Je parlais d'éviter les recopie *inutiles* qui consomment
(inutilement, donc...) des ressources sans autre effet que de rendre le
code moins explicite. Pas de faire l'impasse sur les traitements
nécessaires...


C.q.f.d. (ce qu'il fallait dire).

--
Olivier Miakinen
Non, monsieur le juge, je vous le jure : jamais je n'ai cité
Bruxelles dans ma signature.


Avatar
John GALLET
Re,

Dans ce cas, la syntaxe :
$sql = "insert into matable(var1) values($my_array[test1])";
est tout aussi légale, et encore plus limpide.


En effet, mais c'est le seul cas où ne pas utiliser les ' dans un nom de
tableau indexé est légal sans risques. Donc personnellement je la
déconseille pour ne pas prendre de mauvaises habitudes.

La syntaxe proposée par Bruno (tout aussi SQLement fausse que la tienne,
il manque des ' si var1 est un (var)char(2)) est peut-être lourde mais
rappelle deux choses :

1) quand on a un problème de nommage, comme en shell unix, on peut
utiliser les {} pour préciser la syntaxe d'une variable. Utile pour
construire un nom de variable dynamique par exemple. (1)

2) on doit toujours utiliser des quotes dans le nom d'un index de
tableau type hash table.

Enfin tout ceci, qui ne sont que des questions de lisibilité, est
surtout habitudes de chaque développeur, et comme d'hab, l'essentiel
c'est de savoir ce qu'on fait.

a++;
JG

(1) ce qui est ce que j'utilise pour récupérer un tableau de valeurs en
construisant dynamiquement une variable nommée avec un compteur, syntaxe
100% compatible avec tous les navigateurs de tous les temps,
(tré)passés, présents, ou futurs, ce qui n'est pas garanti avec une
syntaxe incluant [] dans le nom de la variable.

Avatar
Olivier Miakinen

*Dans ce cas*, la syntaxe :
$sql = "insert into matable(var1) values($my_array[test1])";
est tout aussi légale, et encore plus limpide.


En effet, mais c'est le seul cas où ne pas utiliser les ' dans un nom de
tableau indexé est légal sans risques. Donc personnellement je la
déconseille pour ne pas prendre de mauvaises habitudes.


C'est bien pourquoi j'ai écrit « dans ce cas » (car l'exemple que j'ai
simplifié n'en avait pas non plus).

Il est d'ailleurs facile de les rajouter :
$sql = "insert into matable(var1) values('$my_array[test1]')";

La syntaxe proposée par Bruno (tout aussi SQLement fausse que la tienne,
il manque des ' si var1 est un (var)char(2)) est peut-être lourde mais
rappelle deux choses :

1) quand on a un problème de nommage, comme en shell unix, on peut
utiliser les {} pour préciser la syntaxe d'une variable. Utile pour
construire un nom de variable dynamique par exemple. (1)


Oui.

2) on doit toujours utiliser des quotes dans le nom d'un index de
tableau type hash table.


Oui, si tu considères que les doubles quotes avant « insert » et après
la parenthèse fermante font partie de ta règle (je ne parle bien sûr que
de PHP ici, pas de shell Unix).

Enfin tout ceci, qui ne sont que des questions de lisibilité, est
surtout habitudes de chaque développeur, et comme d'hab, l'essentiel
c'est de savoir ce qu'on fait.


[OUI]


Avatar
Guillaume Bouchard
John GALLET wrote:
construire un nom de variable dynamique par exemple. (1)

(1) ce qui est ce que j'utilise pour récupérer un tableau de valeurs en
construisant dynamiquement une variable nommée avec un compteur, syntaxe
100% compatible avec tous les navigateurs de tous les temps,
(tré)passés, présents, ou futurs, ce qui n'est pas garanti avec une
syntaxe incluant [] dans le nom de la variable.


Tient, je croyais être le seul psycopathe à faire cela.

Je confirme, j'ai déjà eu des problèmes je ne sais plus pourquoi ni
comment, mais à cause d'une connerie du genre (et pas avec des
antiquités de navigateurs.)

--
Guillaume.
"Membre du mouvement de libération des pouples"

1 2 3 4