Programmer en PHP de façon optimisée

Un article de LaPageDuJour.

Aller à : Navigation, Rechercher

Le PHP est un langage intéressant qui permet de faire beaucoup de choses mais c'est aussi un langage relativement lent. Dans certains cas, programmer de façon optimisée peut rapidement de venir une nécessité.

Sommaire

[modifier] A quoi ça sert ?

Programmer de façon optimisée sert à servir plus de monde avec la même architecture. C'est particulièrement recommandé quand vous êtes dans une situation de surcharge avérée ou potentielle.

[modifier] Le moins d'instructions possible

Le temps d'exécution d'une instruction en PHP n'est pas très long en lui même, c'est le passage d'une instruction à une autre et les tests conditionnels qui ralentissent beaucoup le code. Evitez donc :

  • De créer des fonctions qui ne rajoutent presque rien au framework PHP déjà présent. Pour cela, vérifiez autant que possible que vous connaissez bien toutes les fonctions autour du domaine nécessitant la création d'une fonction personnalisée.
  • De faire des tests inutiles ou plus "correctes" parce que ça fait mieux

Exemple de code inutile :

if ( ! isset( $i ) || $i == '' || $i == 0 )
   // action

Vous irez trois fois plus rapidement en tapant :

if ( ! $i ) 
   // action
  • De chargez un certain nombre de données (genre 50 variables) depuis un fichier sans les serializer

Au lieu de faire une inclusion des données de cette façon :

require('donnees.php');

A la place, chargez un fichier de données serializées que vous déserialiserez par la suite :

$data = unserialize( file_get_contents( 'donnees.ser' ) );

Pour le construire, ce n'est pas tellement plus compliqué :

if ( ! file_exists( 'donnees.ser' ) ) {
   require('donnees.php');
   file_put_contents( 'donnees.ser', serialize( $data ) );
}

Grâce à ce code, vous économiserez tout le temps de chargement de variables. De part les manipulation de chaine de serialization, vous allez effectivement consommez plus de mémoire. Mais souvent en PHP, la consommation de mémoire est beaucoup moins coûteuse que le temps d'execution de commandes équivalentes.

  • De faire des inclusions d'objets ou de fonctions que vous n'utiliserez pas. le require_once de PHP est fait justement pour que vous puissiez faire des inclusions un peu partout sans vous souciez de savoir si les données sont déjà chargées ou pas.

[modifier] Pas trop d'objet

Vous trouvez la programmation objet cool ou vraiment pratique ? Il n'y a que dans le cas où la programation objet va vous faire gagner du temps ou gagner en lisibilité qu'il faut l'adopter. Le modèle tout objet est inadapté au PHP.

En effet, en PHP, charger un objet est un ensemble d'instructions executer pour créer sa présentation. Il faut ensuite l'instancier, donc utiliser sans doute votre constructeur. Cette étape de création dynamique de l'objet (PHP est un langage de script donc tout est dynamique) prend beaucoup de temps et de mémoire. Evitez donc de mettre des objets à toutes les sauces. Typiquement les objets qui valent vraiment le coup d'être créé sont :

  • La gestion de la base de données
  • La génération de documents PDF
  • Du traitement personnalisé d'image
  • Un système de facturation

Note : Avec certains optimiseurs PHP, le chargement des classes PHP peut être gardé en mémoire et ainsi diminuer le coût (en ressources) que représente l'utilisation d'objets.

[modifier] Chargez au besoin

En PHP, tout est chargé dynamiquement. Si vous faites une inclusion systématique de toutes les librairies que vous utilisez dans votre projet, vous allez significativement ralentir vos programmes. Faites en sortes de ne charger que ce qui est nécessaire au fonctionnement de vos programmes.

require_once('./include/fonctions/traitements_perso.fonc.php');
$retour = traitement_perso1( $var + 'toto' );

[modifier] Quelques petits trucs

[modifier] Les guillemets simple au lieu des quillements doubles

Essayez d'utiliser autant que possible des guillements simple (') plutôt que des guillements double ("), en effet les guillements simple ne font pas l'objet d'analyse des variable (comme $var) ni de reconnaissance des caractères spéciaux (comme \n).

[modifier] foreach

foreach est une instruction de base qui est peu connue en PHP car inexistante dans le langage C, cependant elle permet de gagner beaucoup de temps.

Si on part d'un code qui affiche le contenu d'un tableau de façon classique (mais idiote) :

for( $i = 0; $i < count($tab); $i++ ) {
   echo "* ".$tab."<br />\n";
}

Le "count" du tableau est recalculé à chaque passage de boucle, il vaut mieux le caculer avant :

$nb  = count( $tab );
for( $i = 0; $i < $nb; $i++ ) {
   echo "* ".$tab[$i]."<br />\n";
}

Mais le code le plus rapide (et finalement le plus facile à lire) sera obtenu avec foreach :

foreach( $tab as $v ) {
   echo '* '.$v."<br />\n";
}

[modifier] Les expressions régulières

On dit beaucoup de n'importe quoi sur les expressions régulières.

Il est vrai qu'elles permettent de faire des traitements beaucoup plus rapidement que si vous faisiez un traitement à partir de fonctions PHP pures dans de nombreux cas, cependant, les fonctions PHP de traitement de chaines sont très performantes. Ainsi, aucune expression régulière fera plus rapidement le travail que fait str_replace.

[modifier] Serialisez

Je me permet d'insister encore un peu plus sur ce point. Pensez à sérialiser vos données que c'est nécessaires. La serialization est particulièrement utile lorsque vous souhaitez mettre en cache des données logiques (et non des rendus).

Ainsi, si vous générez des rapports de multiple façon, pensez à mettre en cache les données sources des rapports (si celles ci restent compactes (moins 100 Ko)).

[modifier] La base de données

[modifier] Le moins de requêtes

Essayez autant que possible de faire tous les traitements sur la base de données. Générer, attendre l'exécution et traiter le retour d'une requête SQL doit être minimisé autant que possible. Favorisez autant que possible les longues requêtes qui effectuent le gros du traitement.

[modifier] Les index

Dès que vous avez plus de 100 éléments dans une table, pensez bien à vérifier que celle ci contient de bon index. Si cette table fait l'objet de beaucoup d'accès en écriture, faites attention à ne pas mettre d'index superflus.

[modifier] Eviter les contraintes

Ne mettez pas de contraintes type "UNIQUE" ou "FOREIGN KEY" si ce n'est pas strictement nécessaire. Dans le cas des FOREIGN KEY, il est souvent préférable (notamment pour des bases de données avec beaucoup de changements) de ne pas les utiliser et d'ensuite seulement faire du nettoyage.

Ainsi pour supprimer les données d'une table "utilisateurs_config" pour laquelle il n'y aurait plus de données dans la table "utilisateurs", vous auriez intérêt à taper :

DELETE 
FROM       `utilisateurs_config` AS `c`
LEFT JOIN  `utilisateurs`        AS `u` ON `c`.`utilisateur_id`=`u`.`id`
WHERE      `u`.`id` IS NULL;

Cette syntaxe signifie "Lie la table de utilisateurs_config à utilisateurs. Si l'identifiant de la table utilisateur est nul (c'est à dire qu'il n'existe pas), supprime les données de la table utilisateurs_config".

Pour être bien honnête, cette requête peut s'exécuter de façon assez lente (à partir d'un million de données par exemple). Mais elle vous permettra d'économiser bien plus de temps que le temps cumulé à vérifier des FOREIGN KEY. Et ce ne serait-ce que parce que bien souvent les identifiant unique d'un utilisateur (par exemple) sont stocké dans la session PHP.

[modifier] Les sessions

Les sessions sont un mécanisme très simple et très efficace de PHP. Il vous ait fortement recommandé de les utiliser dans tous vos programmes.

[modifier] Où et comment ?

Elles peuvent être utilisées pour des données (de préférence assez petite) qui devront être utilisées fréquemment et/ou des données confidentielles.

[modifier] Limites

  • Les sessions ne se partagent pas entre plusieurs serveurs. Si vous avez une architecture nécessitant plusieurs serveurs web en front-end (répondant aux clients), il vous faudra donc inventer un système pour répartir les clients entre les différents serveurs et reconstruire (voir transférer) les session de manière transparente.
  • Les sessions sont par défaut créées dans le répertoire "/tmp"

[modifier] Petit plus

  • Si vous avez besoin de performances, montez votre répertoire de session en mémoire virtuelle :

Vous devrez taper :

mkdir -p /sessions
mount -t tmpfs /dev/null /sessions

et modifier/ajouter la ligne dans php.ini :

session_path=/sessions

[modifier] Les frameworks

Les Framework qui doivent être implémentés au coeur de votre programme ralentissent votre code. Il est toujours préférable de se créer son propre framework et de l'améliorer avec le temps.