Conseils de programmation en PhP
Je propose que chacun place ici des conseils quant à la programmation en PHP. Ces conseils seraient plutôt orientés vers les performances, le respect de la syntaxe etc/ que la clarté du code et sa présentation, et ne doivent pas forcément concerner directement
WikiNi (bien que le but soit de les appliquer dans ce cadre). Il ne doit donc pas s'agir de
DocDeveloppeurNormesEtRecoDeDeveloppement...
Chaines de carractères
En
PhP, il existe trois syntaxes différentes pour les chaines de caractères:
- Les guillemets simples: '
- Les guillemets doubles: "
- La syntaxe Here Doc, qui se comporte comme les guillemets doubles sauf qu'il ne faut pas échapper ceux-ci: <<<tag\n chaine \ntag; (très peu utilisée car pas très pratique en fait...)
Pour rappel, voici les différence entre les deux:
- Dans les guillemets doubles, il est possible d’utiliser les caractères spéciaux tels que les nouvelles lignes ("\n"), les tabulations ("\t"), des caractères en notation hexa ("\x41" donne "A") etc.
- Dans les guillemets doubles, les variables sont remplacées par leur valeur. PhP cherchera le plus long nom de variable possible à partir des "$" qu'il trouve (attention à son existence...)
- Dans les guillemets doubles, il est possible d'utiliser une syntaxe complexe pour accéder à certaines valeurs comme les attributs d'un objet ("{$objet->tableau[$element]->attribut}")
Conséquences:
- Techniquement, pour des chaînes très simples (aucun caractère spécial ni symbole "$") il semblerait d'après les quelques tests que je viens de faire que les deux soient équivalents à l'exécution. (en revanche à parser, aucune idée)
- Pour des chaînes contenant un "$" (non suivi de caractères formant une variable), la syntaxe aux guillemets doubles dévient beaucoup plus lente. En effet PhP doit chercher après d'éventuelles variables à remplacer, même s'il n'en trouve pas...
- Pour des chaînes contenant des variables, il doit y avoir des cas où l'un est plus avantageux et certains pour lesquels c'est l'autre. A première vue, il semblerait que la syntaxe aux guillemets simple reste plus rapide pour des cas simples:
<?php
function mtime(){
list($m,$s) = explode(' ', microtime());
return $s + (float) $m;
}
$var = 'salut';
$t1 = mtime();
$v1 = "";
for($i = 1; $i <= 1000; $i++) $v1 = "textetexte $var textetexte";
$t2 = mtime();
sleep(1); // on laisse les choses se calmer...
$t3 = mtime();
$v2 = '';
for($j = 1; $j <= 1000; $j++) $v2 = 'textetexte ' . $var . ' textetexte';
$t4 = mtime();
echo 'Temps1 : ' . ($t2 - $t1) . '<br />Temps2 : ' . ($t4 - $t3);
/*
* Par exemple:
* Temps1 : 0.0023901462554932
* Temps2 : 0.0011210441589355
*/
?>
- Pour écrire du code Html, la syntaxe aux guillemets simples est en général beaucoup plus pratique puisqu'elle ne nécessite pas d'échapper les guillemets doubles (forcément...)
Il me semble avoir lu un jour des conseils disant d'utiliser la synthaxe aux guillemets simples dès que possible, car elle était plus performante... Je ne sais malheureusement plus où, mais depuis lors je respecte cela... De toute façon ça me parait logique, et ça ne peut pas faire de mal. (De plus je trouve que les guillemets simples ont comme un air plus 'léger' mais ce n'est qu'une préférence...)
Accès aux caractères d'une chaine
Dans les anciennes versions de
PhP, on accédait aux caractères comme s'il s'agissait des éléments d'un tableau. Cette synthaxe, bien qu'elle soit toujours utilisable, est obsolète depuis php4, et vous devez utiliser des accolades à la place (
$chaine{23}). N'oubliez pas que le premier caractère se trouve à l'indice 0, et donc le dernier à
strlen($chaine) - 1.
Utilisation des objets
Avant php5, quand vous passiez un objet en argument d'une fonction (ou quand vous le stockiez dans une nouvelle variable), celui-ci était entièrement copié. Pour éviter cela, travaillez par référence:
<?php
function Foo(&$object) {
// instructions
return $newObject;
}
$myObj = new MyClass();
$myNewObj = &Foo($myObj);
$temp = &$myNewObj;
?>
Le passage par référence n'est pas important pour les autres types de variables, à moins que vous ne vouliez en modifier leur valeur à l'intérieur de votre fonction.
Requêtes SQL
Eviter toujours de placer des requêtes à l'intérieur de boucles !
En général il y a toujours moyen de construire une requête dans une boucle, et ensuite de l'exécuter en un coup. Par exemple:
-
Pour les requêtes d'insertion:
<?php
// mauvais
foreach($tableau as $id => $valeur) @mysql_query("INSERT INTO matable (id, nom) VALUES ($id, '$valeur')";
// bon
$sql = 'INSERT INTO matable (id, nom) VALUES ';
$first = true;
foreach($tableau as $id => $valeur) {
$sql .= ($first ? '':', ') . "($id, '$valeur')";
if($first) $first = false;
}
@mysql_query($sql);
?>
-
Pour les requêtes de sélection:
<?php
// mauvais
$table = array();
foreach($tableau as $valeur) {
$result = @mysql_query("SELECT * FROMM matable WHERE nom = '$valeur'");
$table[] = @mysql_fetch_assoc($result);
}
// bon, mais n'oubliez pas de demander un tri pour obtenir le même résultat...
$sql = 'SELECT * FROM matable WHERE nom IN (';
$first = true;
foreach($tableau as $id => $valeur) {
$sql .= ($first ? '':', ') . "'$valeur'";
if($first) $first = false;
}
$result = @mysql_query($sql . ') ORER BY nom DESC');
for($table = array(); $ligne = @mysql_fetch_assoc($result); $table[] = $ligne) ;
?>
Protection des fichiers
Quelqu'un propose dans la documentation des
Constantes Magiques le code suivant pour protéger un fichier de tout appel direct, à tester mais je pense que c'est fiable, et d'ailleurs que c'est le moyen de protection le plus simple qui soit (aucune constante à vérifier, fonctionne n'importe où):
- if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME'])) {
exit;
}
Le système de vérification de l'existence d'une constante (dans wikini:
WIKINI_VERSION) reste cependant bon, sauf que si l'on veut utiliser un fichier de
WikiNi dans un autre contexte (mettons qu'on veuille par exemple colorer une source en delphi dans son site web, en utilisant le fichier coloration_delphi.php), on est obligé de définir la constante WIKINI_VERSION...