PHP : la bonne pratique

Apprendre les bonnes pratiques de programmation en PHP

| Josh Lockhart | Phil Sturgeon |

Ce tutoriel est une traduction adaptée du livre électronique « PHP, The Right Way » écrit par Josh Lockhart, Phil Sturgeon avec plusieurs contributions d'experts PHP. Le livre est inspiré de la documentation officielle de PHP.

Il s'agit, dans ce tutoriel, d'une compil de bonnes pratiques que vous allez apprendre pour bien programmer en PHP.

Dans cette adaptation, nous mettons à contribution les ressources de Developpez.com pour enrichir le contenu.

Un espace vous est proposé sur le forum pour réagir sur ce tutoriel.

Commentez

- Titre : PHP : la bonne pratique

- Auteurs : Josh Lockhart, Phil Sturgeon

- Parution : 10 décembre 2017

- Public visé :

- Licence : Le contenu de cet article est rédigé par Josh Lockhart et est mis à disposition selon les termes de la Licence Creative Commons Attribution - Pas d'Utilisation Commerciale 3.0 non transposé. Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright ® 2013 Developpez.com.

Sommaire

- I. Pour démarrer

- I-A. Utiliser la dernière version stable (7.0)

- I-B. Serveur web intégré

- I-C. Installation sous Mac

- I-D. Installation sous Windows

- I-E. Vagrant

- I-E-1. Un coup de pouce

- II. Normes

- III. Les points importants du langage

- III-A. Les paradigmes de programmation

- III-A-1. Programmation orientée objet

- III-A-2. Programmation fonctionnelle

- III-A-3. Métaprogrammation

- III-B. Les espaces de noms

- III-C. La bibliothèque PHP standard

- III-D. L'interface en ligne de commande

- III-E. XDebug

- IV. La gestion des dépendances

- IV-A. Composer et Packagist

- IV-A-1. Comment installer Composer

- IV-A-2. Installation sous Windows

- IV-A-3. Comment installer Composer (manuellement)

- IV-A-4. Comment définir et installer les dépendances

- IV-A-5. Mettre à jour vos dépendances

- IV-A-6. Notifications de mise à jour

- IV-A-7. Vérifier vos dépendances pour des raisons de sécurité

- IV-B. PEAR

- IV-B-1. Comment installer PEAR

- IV-B-2. Comment installer un paquet

- IV-B-3. Gérer les dépendances PEAR avec Composer

- V. Pratiques de programmation

- V-A. Les bases

- V-B. La date et le temps

- V-C. Les motifs de conception

- V-D. Travailler avec de l'UTF-8

- V-D-1. Il n'y a pas de recette magique. Faites attention, soyez consciencieux et cohérent.

- V-D-2. UTF-8 au niveau de PHP

- V-D-3. UTF-8 au niveau de la base de données

- V-D-4. UTF-8 au niveau du navigateur web

- VI. Injection de dépendances

- VI-A. Concepts de base

- VI-B. Problèmes complexe

- VI-B-1. Inversion de contrôle

- VI-B-2. Principe d'inversion des dépendances

- VI-C. Conteneur

- VII. Bases de données

- VII-A. Extension MySQL

- VII-B. PDO

- VII-C. Couches d'abstractions

- VII-D. Interagir avec les bases de données

- VIII. Templating

- VIII-A. Bénéfices

- VIII-B. Templates en PHP « pur »

- VIII-C. Templates compilés

- IX. Les erreurs et exceptions

- IX-A. Erreurs

- IX-B. Exceptions

- IX-B-1. Les exceptions SPL

- X. Sécurité

- X-A. La sécurité dans une application web

- X-B. Hachage de mots de passe

- X-C. Filtrage des données

- X-C-1. Nettoyage

- X-C-2. Validation

- X-D. Fichiers de configuration

- X-E. Register Globals

- X-F. Rapport d'erreurs

- X-F-1. Développement

- X-F-2. Production

- XI. Tests

- XI-A. Développement dirigé par les tests (TDD)

- XI-A-1. Test unitaire

- XI-A-2. Test d'intégration

- XI-A-3. Test fonctionnel

- XI-A-4. Outils pour les tests fonctionnels

- XI-B. Behavior Driven Development

- XI-B-1. Liens sur le BDD

- XI-C. Outils de test complémentaire

- XI-C-1. Liens vers les outils

- XII. Les serveurs et le déploiement

- XII-A. Platform as a Service (PaaS)

- XII-B. Serveurs virtuels et dédiés

- XII-B-1. nginx et PHP-FPM

- XII-B-2. Apache et PHP

- XII-C. Hébergement mutualisé

- XII-D. Constuire et déployer votre application

- XII-D-1. Outil de construction automatique

- XII-D-2. Intégration continue

- XIII. Cache

- XIII-A. Cache du bytecode

- XIII-B. Cache des objets

- XIV. Documentation du code

- XIV-A. PHPDoc

- XV. Ressources

- XV-A. Officielles

- XV-B. Mentorat

- XV-C. Fournisseurs PaaS pour PHP

- XV-D. Frameworks

- XV-E. Composants

- XV-F. Livres

- XV-F-1. Livres gratuits

- XV-F-2. Livres payants

- XVI. Communauté

- XVI-A. PHP User Groups

- XVI-B. Conférences PHP

- Note de la rédaction Developpez.com

I - Pour démarrer

I-A - Utiliser la dernière version stable (7.0)

Si vous venez juste de commencer à utiliser PHP, prenez soin de débuter avec la dernière version stable de PHP. Le PHP a fait de grands progrès en ajout de puissantes fonctionnalités au cours des dernières années. Le moteur de PHP (Zend engine 3) a par ailleurs été largement réécrit pour être beaucoup plus rapide que les versions précédentes.

Vous trouverez encore de nombreuses références à PHP 5.x dont la dernière itération est la 5.6. Si vous vous retrouvez à maintenir du code 5.x, n'hésitez pas à migrer vers cette dernière version stable. La migration vers la version 7.0 reste néanmoins très aisée, car il n'existe pas énormément de changements incompatibles.

Ne vous laisser pas avoir par le numéro de version mineure entre PHP 5.2 et 5.6, cela représente d'importantes améliorations. Si vous cherchez des informations sur l'utilisation d'une fonction particulière, n'hésitez pas à consulter la documentation sur le site php.net.

I-B - Serveur web intégré

Vous pouvez commencer à apprendre PHP sans avoir à installer et configurer un serveur web (vous devrez utiliser au minimum PHP 5.4). Pour démarrer le serveur intégré, exécutez la ligne de commande suivante dans un terminal à la racine de votre projet :

php -S localhost:8000

Autres exemples d'utilisations de PHP en ligne de commande

I-C - Installation sous Mac

Le système d'exploitation OSX contient une version précompilée de PHP, mais est généralement en retard sur la dernière version stable. Lion contient la version 5.3.6, Moutain la 5.3.10 et Mavericks la 5.4.17.

Pour mettre à jour la version de PHP sur OSX vous pouvez passer via de nombreux gestionnaires de paquets, php-osx de Liip étant recommandé.

L'autre option est de le compiler soi-même. Dans ce cas, faites attention à ce que l'IDE Xcode soit installé ou bien son substitut en ligne de commande téléchargeable sur le Mac Developer Center d'Apple.

Pour une installation « tout-en-un » incluant PHP, le serveur web Apache et la base de données MySQL, le tout contrôlé par une jolie interface graphique, essayez MAMP ou XAMPP.

I-D - Installation sous Windows

PHP est disponible sous Windows de plusieurs façons. Vous pouvez télécharger les binaires et jusqu'à récemment, vous pouviez utiliser un installateur « .msi ». Cependant il n'est plus maintenu depuis la version 5.3.0.

Pour l'apprentissage et le développement en local, vous pouvez dorénavant utiliser le serveur intégré à PHP 5.4+, ainsi vous n'aurez plus à vous soucier de la configuration du serveur web. Si vous souhaitez un système « tout-en-un » incluant un serveur web et MySQL alors des outils tels que WPI, Zend Server CE, XAMPP ou encore WAMP vous permettront d'avoir un environnement de développement complet rapidement. Ceci étant dit, ces outils sont différents de ce que l'on trouve en production donc faites attention sur les différences d'environnement si vous travaillez sur Windows et déployez sur Linux.

Si vous désirez utiliser Windows comme plateforme de production alors, le serveur IIS7 vous donnera le meilleur compromis entre stabilité et performance. Vous pouvez utiliser phpmanager qui est un plugin graphique pour IIS7 afin d'effectuer les configurations nécessaires pour faire tourner PHP. IIS7 intègre FastCGI prêt à l'emploi, vous n'avez qu'à configurer PHP en tant qu'extension. Pour plus d'informations, visitez le site dédié sur iis.net.

I-E - Vagrant

Faire tourner vos applications sur différents environnements en développement et en production peut vous amener à rencontrer d'étranges bogues lorsque vous passez le code en production. Par ailleurs, il est difficile de maintenir différents environnements à jour avec les mêmes versions pour l'ensemble des bibliothèques utilisées lorsque vous travaillez en équipe.

Si vous développez sur Windows et que vous déployez votre code sur Linux (ou n'importe quoi qui ne soit pas Windows) ou que vous travaillez en équipe, vous devriez penser à utiliser une machine virtuelle. Cela peut paraître compliqué, mais utiliser Vagrant vous permet de mettre en place une machine virtuelle en seulement quelques étapes. Ces systèmes de base peuvent ensuite être configurés manuellement ou via des outils comme Puppet ou Chef. Configurer ces systèmes de façon automatisée est un bon moyen de s'assurer que les différents systèmes mis en place seront configurés de la même manière sans avoir à maintenir une liste de commandes pour l'installation. Vous pouvez aussi « détruire » votre système et en recréer un nouveau de façon entièrement automatisée, ce qui facilite les nouvelles installations.

Vagrant crée des dossiers partagés utilisés pour permettre à l'hôte et à la machine virtuelle d'accéder de façon bidirectionnelle à votre code ce qui signifie que vous pouvez créer et éditer vos fichiers sur le système hôte et exécuter votre code sur la machine virtuelle.

I-E-1 - Un coup de pouce

Si vous avez besoin d'aide pour commencer à utiliser Vagrant, il existe trois services qui pourraient vous être utiles :

- Rove : un service qui vous autorise à prégénérer des builds Vagrant typiques avec PHP. L'installation se fait avec Chef ;

- Puphpet : une interface graphique simple pour mettre en place des machines virtuelles pour développer en PHP. Il se concentre énormément sur PHP. Par ailleurs, des VM locales peuvent être utilisées pour déployer des services cloud. L'installation se fait avec Puppet ;

- Protobox : est composé d'une couche au-dessus de Vagrant et d'une interface web pour installer des machines virtuelles pour le développement web. Un seul document YAML contrôle tout ce qui peut être installé sur la machine virtuelle.

II - Normes

La communauté PHP est large et diverse, composée d'innombrables bibliothèques, de frameworks et de composants. Il est courant pour les développeurs PHP de choisir plusieurs d'entre eux et de les combiner en un seul projet. Il est important que le code PHP adhère (de façon aussi proche que possible) à un style commun pour rendre le partage plus facile entre développeurs et de garder une certaine cohérence avec l'utilisation de code tiers.

Le Framework Interop Group a proposé et approuvé une série de conventions de codage. Celles qui sont liées aux conventions d'écriture sont le PSR-0, PSR-1, PSR-2 et PSR-4. Ces recommandations sont un ensemble de règles que certains projets ont adoptées comme Drupal, Zend, Symfony, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium, etc. Vous pouvez les utiliser dans vos projets ou bien la vôtre si vous en avez une.

Idéalement, vous devriez écrire du code PHP qui adhère à des standards connus. Cela peut être une combinaison des PSR ou un des standards créés par PEAR ou Zend.

- En savoir plus sur PSR-0

- En savoir plus sur PSR-1

- En savoir plus sur PSR-2

- En savoir plus sur PSR-4

- Lire les conventions de codage de PEAR

- Lire les conventions de codage de Zend

- Lire les conventions de codage de Symfony

Vous pouvez utiliser PHP_CodeSniffer pour vérifier que votre code respecte une de ces recommandations. Des plugins pour des éditeurs de texte comme Sublime Text 2 vous permettent d'avoir un aperçu des écarts en temps réel.

Utilisez le PHP Coding Standards Fixer de Fabien Potencier afin de formater automatiquement la syntaxe de votre code selon les standards définis, ce qui vous évite de le faire vous-même à la main.

Faites en sorte que l'infrastructure de votre code et que les noms des variables choisis soient en anglais. Les commentaires peuvent être écrits dans n'importe quelle langue du moment que l'ensemble des personnes ayant à travailler dessus puissent le comprendre.

III - Les points importants du langage

III-A - Les paradigmes de programmation

Le PHP est un langage flexible, dynamique supportant une variété de technique de programmation. Il a énormément évolué au cours des années en ajoutant notamment un solide modèle orienté objet avec PHP 5.0 (2004), les fonctions anonymes et les espaces de noms avec PHP 5.3 (2009) et les « traits » avec PHP 5.4 (2012).

III-A-1 - Programmation orientée objet

Le PHP a un ensemble très complet de principes de programmation orientée objet en prenant en compte le support des classes, des classes abstraites, des interfaces, de l'héritage, des constructeurs, du clonage, des exceptions, etc.

- En savoir plus sur l'orienté objet

- En savoir plus sur les « traits »

III-A-2 - Programmation fonctionnelle

Le PHP supporte les fonctions de « première classe » ce qui signifie qu'une fonction peut être affectée à une variable. Les fonctions définies par l'utilisateur ainsi que les fonctions intégrées au langage peuvent être référencées par une variable et invoquées dynamiquement. Les fonctions peuvent être passées en tant qu'argument à d'autres fonctions (on parle alors de fonctions d'ordre supérieur) et elles peuvent retourner d'autres fonctions.

La récursion est une fonctionnalité permettant à une fonction de s'appeler elle-même, cependant la plupart des fonctions PHP se concentrent sur la partie « itération ».

Les nouvelles fonctions anonymes avec le support pour les fermetures (closures en anglais) sont présentes depuis PHP 5.3 (2009).

Le PHP 5.4 a rajouté la possibilité de lier (« bind ») les fermetures à la portée d'un objet et a aussi amélioré le support pour les « callables » de façon à ce qu'elles puissent être utilisées aussi bien avec les fonctions anonymes (dans la plupart des cas).

- Continuer la lecture sur la programmation fonctionnelle en PHP

- En savoir plus sur les fonctions anonymes

- En savoir plus sur la classe Closure

- Plus de détails sur Closures RFC

- En savoir plus sur les callables

- En savoir plus sur les fonctions invoquées dynamiquement avec

III-A-3 - Métaprogrammation

Le PHP supporte différentes formes de métaprogrammation à travers des mécanismes tels que l'API Reflection et les méthodes magiques. Il existe un grand nombre de méthodes magiques comme __get(), __set(), __clone(), __toString(), __invoke(), etc. permettant aux développeurs d'interférer avec le comportement d'une classe. Les développeurs Ruby répètent souvent que le PHP manque de method_missing, mais cela est pourtant disponible avec __call() and __callStatic().

- En savoir plus sur les méthodes magiques

- En savoir plus sur l'API Reflection

III-B - Les espaces de noms

Comme mentionné plus haut, la communauté PHP a beaucoup de développeurs créant beaucoup de code. Cela signifie que le code d'une bibliothèque PHP peut utiliser le même nom de classe qu'une autre bibliothèque. Quand plusieurs bibliothèques sont utilisées dans le même espace de noms, il peut y avoir des collisions de noms ce qui pose problème.

Les espaces de noms résolvent ce problème. Comme décrit dans le manuel de référence PHP, les espaces de noms peuvent être comparés aux répertoires d'un système de fichiers. De même, deux classes PHP peuvent avoir le même nom si elles sont créées dans des espaces de noms distincts.

Il est important pour vous que vous utilisiez les espaces de noms dans votre code. Ainsi vous et d'autres développeurs pourrez utiliser ce code sans crainte d'entrer en collision avec d'autres bibliothèques.

Une bonne manière d'utiliser les espaces de noms se trouve dans PSR-0 qui vise à fournir un fichier standard, une convention pour les classes et les espaces de noms pour permettre d'avoir du code « plug-and-play ».

En décembre 2013, le PHP-FIG a créé un nouveau standard d'autochargement: PSR-4, qui un jour va probablement remplacer PSR-0. Pour le moment, les deux sont utilisables étant donné que PSR-4 ne tourne que sur PHP 5.3+ et que beaucoup de projets implémentent PSR-0. Si vous allez utiliser un standard d'autochargement pour une nouvelle application ou un paquetage alors vous devriez certainement voir du côté de PSR-4.

- En savoir plus sur les espaces de noms

- En savoir plus sur PSR-0

- En savoir plus sur PSR-4

III-C - La bibliothèque PHP standard

La bibliothèque standard PHP (SPL en anglais) est fournie avec PHP et donne accès à une collection de classes et d'interfaces. Elle est composée de classes permettant de manipuler les structures de données les plus courantes comme les piles (stack), les files (queue), le tas (heap) et des itérateurs qui peuvent parcourir ces structures ou vos propres classes implémentant les interfaces SPL.

En savoir plus sur la SPL

III-D - L'interface en ligne de commande

Le PHP a été créé principalement pour écrire des applications web, mais il peut être tout aussi utile pour écrire des programmes en ligne de commande (command line interface ou CLI en anglais). Ces programmes peuvent vous aider à automatiser les tâches les plus courantes comme les tests, le déploiement et l'administration du site.

Les programmes PHP CLI sont puissants, car vous pouvez directement utiliser le code de votre application sans avoir à créer et à réaliser une interface web « sécurisée ». Faites juste attention à ne pas mettre vos scripts PHP à la racine de votre répertoire web public.

Essayez de faire tourner PHP en ligne de commande: > php -i

L'option -i va afficher votre configuration exactement comme la fonction phpinfo.

L'option -a fournit un terminal interactif similaire aux terminaux Ruby (IRB) et Python. Il existe par ailleurs d'autres options utiles.

Écrivons un simple programme CLI « Hello, $nom ». Pour faire vos essais, créez un fichier nommé hello.php et écrivez le code ci-dessous.

1. <?php

2. if ($argc != 2) {

3. echo "Usage: php hello.php [nom].\n";

4. exit(1);

5. }

6. $nom = $argv[1];

7. echo "Hello, $nom\n";

Le PHP crée deux variables spéciales basées sur les paramètres passés au script. La variable $argc est un entier contenant le nombre de paramètres et $argv est un tableau contenant chacune des valeurs des paramètres. Le premier paramètre est toujours le nom du script PHP, dans notre cas hello.php.

L'expression exit() est utilisée avec un nombre différent de zéro pour indiquer au terminal que la commande a échoué. Les codes de sortie les plus communs se trouvent ici.

Pour exécuter le script ci-dessus depuis le terminal :

1. > php hello.php

2. Usage: php hello.php [nom]

3. > php hello.php world

4. Hello, world

- En savoir plus sur l'exécution de PHP en ligne de commande

III-E - XDebug

Un des outils les plus utiles dans le développement logiciel est un bon débogueur. Il vous permet de tracer l'exécution de votre code et de surveiller le contenu de la pile. XDebug, le débogueur de PHP, peut être utilisé par de nombreux EDI pour fournir des fonctionnalités telles que les points d'arrêt ou l'inspection de la pile. Il permet aussi à des outils comme PHPUnit et KCacheGrind de faire de l'analyse pour la couverture de code et du « profiling ».

Si vous vous trouvez dans une closure, que vous avez recours à var_dump/print_r et que vous ne trouvez toujours pas de solution - alors vous devriez utiliser un débogueur.

Installer XDebug peut se révéler compliqué, mais l'une des fonctionnalités les plus importantes est le « débogage à distance » - Si vous développez du code localement et que vous testez ensuite sur une machine virtuelle, voire un autre serveur alors le débogage à distance vous permettra de la faire sans problème.

Traditionnellement, vous allez modifier votre fichier VHost Apache ou votre .htaccess avec les valeurs suivantes :

1. php_value xdebug.remote_host=192.168.?.?

2. php_value xdebug.remote_port=9000

Le « remote host » et « remote port » correspondent à l'IP de votre ordinateur et au port sur lequel votre EDI va écouter. Il suffit alors de configurer votre EDI pour écouter sur le port choisi et de charger l'URL :

1. http://votre-site.exemple.com/index.php?XDEBUG_SESSION_START=1

Votre EDI va maintenant intercepter l'état courant au fur et à mesure que le script s'exécute vous permettant de mettre des points d'arrêt et d'inspecter les valeurs en mémoire.

Les débogueurs graphiques permettent de se déplacer très facilement dans le code, d'inspecter les variables et d'évaluer du code à l'exécution. Beaucoup d'EDI ont un support intégré ou via un plugin pour le débogage avec xdebug. MacGDBp est un xdebug gratuit, open source pour Mac.

- En savoir plus sur XDebug

- En savoir plus sur MacGDBp

IV - La gestion des dépendances

Il existe une tonne de bibliothèques PHP, de frameworks et de composants pour gérer les dépendances. Votre projet va surement utiliser plusieurs d'entre eux — ce sont les dépendances d'un projet. Jusqu'à récemment, le PHP n'avait pas de moyen fiable pour gérer ces dépendances. Même si vous les gériez de façon manuelle, vous deviez toujours vous inquiéter des autoloaders. Mais plus maintenant.

À l'heure actuelle, il existe deux gestionnaires de packaging pour PHP - Composer et PEAR. Lequel correspond le mieux à vos attentes ? Cela dépend de la taille de votre projet.

- Utilisez Composer pour la gestion des dépendances d'un seul projet.

- Utilisez PEAR lorsque vous devez gérer les dépendances pour un système complet.

En général, les packages Composer seront disponibles uniquement pour les projets auxquels vous les aurez explicitement spécifiés alors qu'un package PEAR sera disponible pour tous vos projets PHP. Bien que PEAR semble être la meilleure approche au premier regard, il existe de nombreux avantages à utiliser une approche de gestion des dépendances par projet.

IV-A - Composer et Packagist

Composer un excellent gestionnaire de dépendances pour PHP. Listez les dépendances de votre projet dans un fichier composer.json et en quelques commandes, Composer va automatiquement télécharger ces dépendances et les installer pour vous.

Il existe déjà un grand nombre de bibliothèques PHP compatibles avec Composer, prêtes à être utilisée par votre projet. Ces « paquets » sont listés sur Packagist, le répertoire officiel pour les bibliothèques compatibles avec Composer.

IV-A-1 - Comment installer Composer

Vous pouvez installer Composer localement (dans votre répertoire de travail courant; bien que cela ne soit plus recommandé) ou globalement (par ex., /usr/local/bin). Supposons que vous vouliez installer Composer localement. Depuis la racine de votre projet, tapez :

1. curl -s https://getcomposer.org/installer | php

Cela va télécharger composer.phar qui est une archive PHP binaire. Vous pouvez le lancer avec PHP pour gérer vos dépendances.

Attention : si vous redirigez du code téléchargé directement dans un interpréteur, veuillez d'abord lire le code en ligne pour confirmer qu'il est sûr.

IV-A-2 - Installation sous Windows

Pour les utilisateurs de Windows, la façon la plus pratique de mettre en place Composer est d'installer ComposerSetup qui va faire tout le travail pour vous (modification du $PATH) afin d'appeler l'utilitaire Composer directement depuis votre terminal.

IV-A-3 - Comment installer Composer (manuellement)

Installer manuellement Composer est une technique avancée. Cependant, il existe diverses raisons pour lesquelles un développeur aurait besoin de le faire. L'installation interactive va vérifier que la version installée :

- contient une version suffisamment récente pour être utilisable ;

- peut exécuter correctement des fichiers .phar ;

- a des permissions suffisantes sur certains répertoires ;

- possède des extensions problématiques qui ne seront alors pas chargées ;

- a les bonnes configurations au niveau du fichier php.ini.

Étant donné qu'une installation manuelle n'effectue aucune de ces vérifications, vous devrez décider vous-même du meilleur compromis à faire. Voici comment obtenir Composer manuellement :

1. curl -s https://getcomposer.org/composer.phar -o $HOME/local/bin/composer

2. chmod +x $HOME/local/bin/composer

Le chemin $HOME/local/bin (ou le répertoire de votre choix) doit être dans la variable d'environnement $PATH. Ainsi, la commande composer peut être accessible de partout.

Quand vous tombez sur de la documentation qui indique de lancer Composer avec PHP composer.phar install, vous pouvez substituer cette commande avec : composer install.

La section suivante suppose le fait que vous avez installé Composer « globlalement ».

IV-A-4 - Comment définir et installer les dépendances

Composer garde la trace des dépendances de votre projet dans un fichier nommé composer.json. Vous pouvez le maintenir vous-même à la main ou utiliser Composer. La commande composer require ajoute une dépendance à votre projet et, si vous n'avez pas de fichier composer.json, va le créer. Voici un exemple qui ajoute Twig en tant que dépendance pour votre projet :

1. composer require twig/twig:~1.8

Alternativement, la commande composer init va vous guider à travers la création du fichier composer.json. De toute manière, une fois que ce fichier est créé, vous pouvez indiquer à Composer de télécharger et d'installer vos dépendances dans le répertoire vendors/. Cela s'applique aussi aux projets que vous avez téléchargés et qui possèdent déjà un fichier composer.json :

1. composer install

Ensuite, ajoutez cette ligne dans le fichier PHP principal de votre application, cela va dire à PHP d'utiliser l'autochargeur de Composer pour les dépendances de votre projet :

1. <?php

2. require 'vendor/autoload.php';

Maintenant si vous utilisez les bibliothèques dont votre projet est dépendant, elles seront chargées à la demande.

IV-A-5 - Mettre à jour vos dépendances

Composer crée un fichier appelé composer.lock qui stocke la version exacte de chaque paquet qui a été téléchargé quand vous avez exécuté pour la première fois php composer.phar install. Si vous partagez votre projet avec d'autres développeurs et que le fichier composer.lock y est inclus, alors ils auront les mêmes versions que vous. Pour mettre à jour ces dépendances, exécutez php composer.phar update.

Cela est très pratique quand vous définissez les versions requises de façon flexible. Par exemple, une version exigée de ~1.8 signifie « tout ce qui est plus récent que 1.8.0, mais inférieur à 2.0.x-dev ». Vous pouvez aussi utiliser le joker * par exemple 1.8.*. À partir de là, la commande php composer.phar update va mettre à jour vos dépendances à la dernière version en suivant les restrictions demandées.

IV-A-6 - Notifications de mise à jour

Pour recevoir les notifications de nouvelles versions, vous pouvez vous enregistrer sur VersionEye qui est un service web qui surveille vos fichiers composer.json sur vos comptes Github et BitBucket et vous envoie des emails avec les nouvelles versions.

IV-A-7 - Vérifier vos dépendances pour des raisons de sécurité

Le Security Advisories Checker est un service web et un outil en ligne de commande qui va examiner votre fichier composer.lock et vous dire si vous avez besoin d'une mise à jour sur chacune de vos dépendances.

En savoir plus sur Composer

IV-B - PEAR

Un autre ancien gestionnaire de paquets que beaucoup de développeurs PHP adorent est PEAR. Il se comporte pratiquement de la même façon que Composer, mais possède des différences notables.

PEAR exige que chaque paquet ait une structure spécifique ce qui veut dire que l'auteur du paquet doit le préparer en vue d'être utilisé par PEAR. Utiliser une bibliothèque qui n'était pas préparée pour PEAR ne marchera pas.

PEAR installe les paquets de façon globale ce qui signifie qu'après les avoir installés ils seront accessibles depuis n'importe quel projet sur le serveur. Cela peut être intéressant si beaucoup de projets se basent sur la même version du même paquet, mais peut poser problème en cas de conflits entre deux projets ayant besoin de versions différentes.

IV-B-1 - Comment installer PEAR

Vous pouvez installer PEAR en téléchargeant l'installateur phar et en l'exécutant. La documentation PEAR a des instructions détaillées pour chaque système d'exploitation.

Si vous utilisez Linux, vous pouvez aussi vous baser sur le gestionnaire de paquets de votre distribution. Par exemple pour Debian et Ubuntu, il existe un paquet s'appelant php-pear.

IV-B-2 - Comment installer un paquet

Si le paquet figure sur la liste des paquets PEAR, vous pouvez l'installer en spécifiant son nom officiel : pear install foo

Si le paquet est hébergé sur un autre canal, vous aurez alors besoin de découvrir ce canal et aussi de le spécifier lors de l'installation.

En savoir plus sur PEAR

IV-B-3 - Gérer les dépendances PEAR avec Composer

Si vous utilisez déjà Composer et que vous voulez installer quelques paquets gérés par PEAR aussi alors vous pouvez utiliser Composer pour gérer les dépendances à PEAR. L'exemple suivant va installer du code de pear2.php.net :

1. {

2. "repositories": [

3. {

4. "type": "pear",

5. "url": "http://pear2.php.net"

6. }

7. ],

8. "require": {

9. "pear-pear2/PEAR2_Text_Markdown": "*",

10. "pear-pear2/PEAR2_HTTP_Request": "*"

11. }

12. }

La première section « repositories » va être utilisée pour faire savoir à Composer qu'il doit « initialiser » (ou « découvrir » selon la terminologie PEAR) le répertoire pear. Ensuite la section require va préfixer le paquet de la façon suivante :

1. pear-channel/Package

Le préfixe « pear » est écrit en dur pour éviter tout conflit étant donné que le canal pear peut être le même que d'autres paquets par exemple. Puis le nom court du canal (ou l'URL complète) peut être utilisé pour référencer dans quel canal se trouve le paquet.

Quand ce paquet est installé, il sera accessible dans votre répertoire de façon automatique grâce à l'autochargeur de Composer :

1. vendor/pear-pear2.php.net/PEAR2_HTTP_Request/pear2/HTTP/Request.php

Pour utiliser ce paquet PEAR, référencez-le simplement de cette façon :

1. $request = new pear2\HTTP\Request();

En savoir plus sur la façon d'utiliser PEAR avec Composer

V - Pratiques de programmation

V-A - Les bases

PHP est un langage vaste permettant aux programmeurs de tout niveau de produire du code non seulement rapidement, mais aussi efficacement. Cependant, en avançant dans le langage, nous oublions parfois les bases que nous avions apprises (ou survolées) de façon un peu légère en faveur de raccourcis et autres mauvaises habitudes. Pour combattre ce problème récurrent, cette section tient à rappeler aux programmeurs les pratiques de programmations de base de PHP.

- Continuer en lisant les bases.

V-B - La date et le temps

Le PHP a une classe nommée DateTime afin d'aider à lire, écrire, comparer et calculer avec les dates et le temps. Il existe beaucoup de fonctions liées aux dates en PHP en plus de DateTime, mais ce dernier fournit une interface orientée objet à la plupart des usages courants. Il peut gérer les fuseaux horaires, mais cela dépasse le cadre de notre introduction.

Pour commencer à travailler avec DateTime, convertissez les chaînes de caractères représentant des dates ou du temps avec la fabrique createFromFormat() ou faites new \DateTime. Utilisez la méthode format() pour convertir la date vers une représentation sous forme de chaîne de caractères.

1. <?php

2. $raw = '22. 11. 1968';

3. $start = \DateTime::createFromFormat('d. m. Y', $raw);

5. echo 'Date : ' . $start->format('m/d/Y') . "\n";

Le calcul des dates avec DateTime est possible à l'aide de la classe DateInterval. DateTime a des méthodes comme add() et sub() qui prennent une variable de type DateInterval en argument. N'écrivez pas du code qui attend que chaque jour ait le même nombre de secondes, car le passage à l'heure d'été/d'hiver et les changements de fuseaux horaires brisent cette assertion. Utilisez plutôt les intervalles de date. Pour calculer ces différences, utilisez la méthode diff(). Cette dernière va retourner un objet DateInterval qui est super facile à afficher.

1. <?php

2. // créer une copie de $start et ajouter un mois et six jours

3. $end = clone $start;

4. $end->add(new \DateInterval('P1M6D'));

6. $diff = $end->diff($start);

7. echo 'Différence: ' . $diff->format('%m mois, %d jours (total: %a jours)') . "\n";

8. // Différence: 1 mois, 6 jours (total: 37 jours)

Avec les objets DateTime vous pouvez utiliser les opérateurs de comparaison :

1. <?php

2. if ($start < $end) {

3. echo "$start est avant $end!\n";

4. }

Un dernier exemple pour faire la démonstration de la classe DatePeriod. Il est utilisé pour itérer sur des évènements récurrents. Il peut prendre deux objets DateTime, start et end, et l'intervalle pour lequel tous les évènements seront retournés.

1. <?php

2. // affiche tous les jeudis entre $start et $end

3. $periodInterval = \DateInterval::createFromDateString('first thursday');

4. $periodIterator = new \DatePeriod($start, $periodInterval, $end, \DatePeriod::EXCLUDE_START_DATE);

5. foreach ($periodIterator as $date) {

6. // affiche chaque date pour la période

7. echo $date->format('m/d/Y') . ' ';

8. }

- En savoir plus sur DateTime

- En savoir plus sur le formatage des dates (les formats et options acceptés)

V-C - Les motifs de conception

Lorsque vous construisez votre application, il est souvent utile d'utiliser des motifs courants dans votre code et dans la structure générale de votre projet. Utiliser ces motifs est utile, car il devient alors plus facile de gérer le code et de permettre aux autres développeurs de comprendre plus rapidement comment tout cela tient.

Si vous utilisez un framework alors la plus grande partie du code métier et la structure du projet se baseront sur ce framework, donc de nombreuses décisions sur les motifs à utiliser seront prises à votre place. Mais c'est à vous de choisir les motifs les plus utiles à utiliser au sein de votre code. Si, d'un autre côté, vous n'utilisez pas de framework pour construire votre application, cela ne vous empêchera pas de choisir un certain nombre de motifs que vous jugerez nécessaires.

Continuer la lecture sur les motifs de conceptions.

V-D - Travailler avec de l'UTF-8

Cette section a été traduite à partir de la page d'Alex Cabal sur les meilleures pratiques PHP et sert de base pour vous donner des conseils sur l'utilisation de l'UTF-8.

V-D-1 - Il n'y a pas de recette magique. Faites attention, soyez consciencieux et cohérent.

Jusqu'à présent PHP n'inclut pas de support bas niveau pour l'Unicode. Il existe des moyens de s'assurer que les chaînes de caractères encodées en UTF-8 seront traitées correctement, mais cela n'est pas facile et demande une attention particulière tout le long de la chaîne de traitement, allant de la page HTML à vos requêtes SQL en passant par le PHP. Les prochains paragraphes vont tenter de vous résumer la bonne approche à adopter face à du contenu Unicode.

V-D-2 - UTF-8 au niveau de PHP

Les opérations basiques sur les chaînes de caractères comme la concaténation ou l'affectation de chaînes à des variables ne demandent rien de particulier en ce qui concerne l'UTF-8. En revanche, la plupart des fonctions manipulant les chaînes comme strpos() et strlen() ont besoin d'une attention particulière. Ces fonctions ont en effet souvent leur contrepartie mb_* comme mb_strpos() et mb_strlen(). Ces fonctions mb_* proviennent de l'extension pour les chaînes de caractères multioctets et ont été conçues spécialement pour les chaînes Unicode.

Vous devez utiliser les fonctions mb_* à chaque fois que vous manipulez une chaîne de caractères Unicode. Par exemple, si vous utilisez substr() sur une chaîne UTF-8, il y a de fortes chances pour que le résultat contienne des caractères à moitié tronqués. La fonction correcte dans ce genre de cas serait d'utiliser mb_substr().

La difficulté réside dans le fait de se souvenir à chaque fois d'utiliser les fonctions mb_* quand c'est nécessaire. Si jamais vous l'oubliez ne serait-ce qu'une seule fois alors votre chaîne Unicode aura de grandes chances d'être incompréhensible en sortie de traitement.

Les fonctions traitant les chaînes n'ont pas toutes leur équivalent mb_*. S'il y en a une qui est dans ce cas alors, vous n'avez pas de chance.

Vous devriez utiliser la fonction mb_internal_encoding() en haut de tous vos scripts PHP (ou en haut d'un fichier d'en-tête global) et la fonction mb_http_output() juste après si vous devez afficher du texte en sortie. Définir explicitement l'encodage de caractères de vos chaînes vous simplifiera énormément la vie.

Par ailleurs, beaucoup de fonctions PHP opérant sur les chaînes ont un paramètre optionnel vous permettant de spécifier l'encodage de caractères. Vous devriez alors toujours indiquer explicitement que vous utilisez de l'UTF-8. Par exemple, la fonction htmlentities() possède une option pour l'encodage des caractères. Notez que depuis PHP 5.4.0, l'UTF-8 est l'encodage par défaut pour htmlentities() et htmlspecialchars().

Finalement, si vous développez et déployez une application utilisant l'UTF-8 sans être certain que l'extension mbstring sera présente, pensez alors à utiliser des alternatives comme le package Composer patchwork/utf8. Il utilisera mbstring si jamais il le trouve sinon il utilisera les fonctions non-UTF8.

V-D-3 - UTF-8 au niveau de la base de données

Si votre script PHP a accès à MySQL, il y a une forte chance que vos chaînes de caractères soient stockées en tant que chaînes non UTF8 même si vous suivez les précautions vues plus haut.

Pour vous assurer que vos chaînes aillent de PHP vers MySQL en UTF-8, vérifiez que votre base de données et les tables qu'elle contient sont toutes enregistrées avec l'encodage de caractères et la collation utf8mb4 et que votre connexion PDO est aussi mise sur cet encodage. Voir l'exemple plus bas. Ceci est extrêmement important.

Notez que pour utiliser le support complet pour UTF-8, vous devez utiliser l'encodage de caractères utf8mb4 et non utf8 ! Voir les détails plus loin pour comprendre pourquoi.

V-D-4 - UTF-8 au niveau du navigateur web

Utilisez la fonction mb_http_output() pour vous assurer que votre script PHP affichera du texte en UTF-8 dans votre navigateur.

Le navigateur devra ensuite être averti par le biais de la réponse HTTP que cette page est encodée en UTF-8. L'approche historique pour faire cela était d'inclure le tag <meta> dans le tag <head>. Cette approche est parfaitement valide, mais indiquer l'encodage directement dans l'en-tête HTTP Content-Type est en fait plus rapide.

1. <?php

2. // Indique à PHP que nous allons effectivement manipuler du texte UTF-8

3. mb_internal_encoding('UTF-8');

5. // indique à PHP que nous allons afficher du texte UTF-8 dans le navigateur web

6. mb_http_output('UTF-8');

8. // Notre chaîne UTF-8 de test

9. $string = 'Êl síla erin lû e-govaned vîn.';

11. // Découpe une sous partie de la chaîne à l'aide d'une fonction multioctet

12. // Notez que la découpe se fait au niveau d'un caractère non ASCII pour la démonstration

13. $string = mb_substr($string, 0, 15);

15. // Connexion à une base de données pour stocker la chaîne transformée

16. // Voir les exemples d'utilisation de PDO dans ce document

17. // Notez la commande `set names utf8mb4`

18. $link = new \PDO(

19. 'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',

20. 'your-username',

21. 'your-password',

22. array(

23. \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,

24. \PDO::ATTR_PERSISTENT => false

25. )

26. );

28. // Stocke notre chaîne en tant que chaîne UTF-8 dans la base de données

29. // Votre base ainsi que ses tables doivent être encodées avec utf8mb4 (character set et collation).

30. $handle = $link->prepare('insert into ElvishSentences (Id, Body) values (?, ?)');

31. $handle->bindValue(1, 1, PDO::PARAM_INT);

32. $handle->bindValue(2, $string);

33. $handle->execute();

35. // Récupère la chaîne que l'on vient juste de stocker pour prouver qu'elle a été correctement stockée

36. $handle = $link->prepare('select * from ElvishSentences where Id = ?');

37. $handle->bindValue(1, 1, PDO::PARAM_INT);

38. $handle->execute();

40. // stocke le résultat dans un objet que l'on affichera dans notre HTML

41. $result = $handle->fetchAll(\PDO::FETCH_OBJ);

43. header('Content-Type: text/html; charset=utf-8');

44. ?><!doctype html>

45. <html>

46. <head>

47. <title>page de test UTF-8</title>

48. </head>

49. <body>

50. <?php

51. foreach($result as $row){

52. print($row->Body);  // Cela devrait correctement afficher notre contenu en UTF-8

53. }

54. ?>

55. </body>

56. </html>

VI - Injection de dépendances

L'injection de dépendances est un mécanisme qui permet d'implanter le principe de l'inversion de contrôle. Il consiste à créer dynamiquement (injecter) les dépendances entre les différentes classes en s'appuyant sur une description (fichier de configuration ou métadonnées) ou de manière programmatique. Ainsi les dépendances entre composants logiciels ne sont plus exprimées dans le code de manière statique, mais déterminées dynamiquement à l'exécution.

Cette citation rend le concept plus compliqué qu'il n'y paraît. L'injection de dépendances fournit un composant avec ses dépendances que ce soit via un constructeur, des appels de méthodes ou la configuration de propriétés. C'est tout.

VI-A - Concepts de base

Nous pouvons démontrer le concept avec un exemple tout bête.

Imaginons que nous ayons une classe Database qui exige un adaptateur (adapter en anglais) pour communiquer avec la base de données. Nous instancions l'adaptateur à l'intérieur du constructeur et créons une dépendance forte. Cela rend les tests compliqués étant donné que la classe Database est fortement couplée à l'adaptateur.

1. <?php

2. namespace Database;

4. class Database

5. {

6. protected $adapter;

8. public function __construct()

9. {

10. $this->adapter = new MySqlAdapter;

11. }

12. }

14. class MysqlAdapter {}

Ce code peut être refactorisé pour utiliser l'injection de dépendances et ainsi délier l'adaptateur de la classe.

1. <?php

2. namespace Database;

4. class Database

5. {

6. protected $adapter;

8. public function __construct(MySqlAdapter $adapter)

9. {

10. $this->adapter = $adapter;

11. }

12. }

14. class MysqlAdapter {}

Maintenant nous fournissons à la classe Database les dépendances nécessaires en argument au lieu de les créer nous-même. Nous pouvons même créer une méthode qui accepterait les paramètres des dépendances afin de les fixer nous-même, ou si la propriété $adapter était public, nous pourrions la définir directement.

VI-B - Problèmes complexe

Si vous avez déjà lu des articles sur l'injection de dépendances, alors vous avez probablement vu des termes comme « Inversion de contrôle » ou « Principe d'inversion de dépendances ». Ces termes sont les problèmes complexes que l'injection de dépendances cherche à résoudre.

VI-B-1 - Inversion de contrôle

L'inversion de contrôle est, comme il le sous-entend, un système cherchant à « inverser le contrôle » en gardant le contrôle organisationnel entièrement séparé des objets. En termes d'injection de dépendances, cela signifie que l'on sépare les dépendances en les contrôlant et en les instanciant ailleurs dans le système.

Pendant des années, les frameworks PHP ont fait de l'inversion de contrôle, cependant la question est devenue : « quelle partie du contrôle doit-on inverser et vers où ? » Par exemple, les frameworks MVC fourniront généralement un super objet ou un contrôleur de base dont les autres contrôleurs doivent hériter pour avoir accès à ses dépendances. C'est ça l'inversion de contrôle, cependant, au lieu de séparer les différentes dépendances, cette méthode ne fait que les déplacer.

L'injection de dépendances nous permet de résoudre ce problème de façon plus élégante en injectant uniquement les dépendances dont nous avons besoin, quand nous en avons besoin, et ce, sans avoir à écrire en dur quelque dépendance que ce soit.

VI-B-2 - Principe d'inversion des dépendances

Le principe d'inversion des dépendances (en anglais Dependency Inversion Principle) correspond au « D » dans « S.O.L.I.D. » qui est un ensemble de principes et de conceptions orientés objet. Il est dit que l'on doit « dépendre des abstractions et non des implémentations ». Cela signifie que nos dépendances doivent se faire sur des interfaces/contrats ou encore sur des classes abstraites plutôt que sur des classes « concrètes ». Nous pouvons facilement refactoriser l'exemple ci-dessus en suivant ce principe.

1. <?php

2. namespace Database;

4. class Database

5. {

6. protected $adapter;

8. public function __construct(AdapterInterface $adapter)

9. {

10. $this->adapter = $adapter;

11. }

12. }

14. interface AdapterInterface {}

16. class MysqlAdapter implements AdapterInterface {}

Il y a plusieurs avantages à ce que la classe Database dépende d'une interface plutôt que de son implémentation.

Imaginons que vous êtes en train de travailler dans une équipe et que l'adaptateur est écrit par un de vos collègues. Dans notre premier exemple, nous aurions d'abord attendu que notre collègue ait fini l'adaptateur avant de pouvoir l'utiliser dans nos tests unitaires. Maintenant que la dépendance correspond à une interface, nous pouvons créer un objet factice implémentant cette interface en sachant que notre collègue construira l'adaptateur en respectant le contrat de base.

Un bénéfice encore plus grand de cette méthode est que notre code est maintenant plus facilement évolutif (scalable en anglais). Si dans un an nous décidons que nous voulons migrer sur un autre type de base de données, alors nous n'avons qu'à écrire et utiliser l'adaptateur qui implémente l'interface spécifique et ainsi, nous n'avons plus besoin de refactoriser du code.

VI-C - Conteneur

La première chose que vous devriez comprendre sur les conteneurs d'injection de dépendances est qu'il ne s'agit pas de la même chose que l'injection de dépendances. Un conteneur est un moyen pratique d'implémenter l'injection de dépendances, cependant, ils peuvent être souvent mal utilisés et devenir un antipattern. Injecter un composant ID en tant que localisateur de services à l'intérieur de vos classes crée sans aucun doute une dépendance plus forte que la dépendance que vous remplacez. Cela rend aussi votre code moins transparent et finalement plus dur à tester.

La plupart des frameworks modernes ont leur propre conteneur d'injection de dépendances qui permettent de brancher vos dépendances ensemble à travers un fichier de configuration. Cela signifie en pratique que vous écrivez du code métier aussi propre et découplé que le framework sur lequel vous vous basez.

VII - Bases de données

Votre code PHP va souvent faire appel aux bases de données pour préserver l'information. Vous avez un certain nombre d'options pour vous connecter et interagir avec votre base de données. L'option recommandée avant PHP 5.1.0 était d'utiliser les pilotes natifs tels que mysql, mysqli, pgsql, etc.

Les pilotes natifs sont géniaux si vous n'utilisez qu'un seul type de bases de données dans votre application, mais si, par exemple, vous utilisez MySQL et un peu de MSSQL ou vous avez besoin de vous connecter à une base Oracle alors vous ne pourrez utiliser les mêmes pilotes. Vous aurez besoin d'apprendre une nouvelle API pour chaque type de BDD — ce qui peut devenir lourd.

VII-A - Extension MySQL

L'extension mysql pour PHP est aujourd'hui au point mort et est officiellement dépréciée depuis PHP 5.5.0 ce qui signifie qu'elle sera retirée dans les prochaines versions. Si vous utilisez n'importe quelles fonctions commençant par mysql_* (comme mysql_connect()) dans votre application, alors cela donnera des erreurs dans votre code. Vous serez donc obligé de faire la transition vers mysqli ou PDO.

Si vous venez de commencer votre projet, alors n'utilisez surtout pas l'extension mysql, mais préférez mysqli ou PDO

- PHP: Choisir une API pour MySQL

- Tutoriel sur les PDO pour les développeurs MySQL

VII-B - PDO

Le PDO est une couche d'abstraction pour se connecter à une base de données — intégrée à PHP depuis la 5.1.0 — qui fournit une interface commune pour communiquer avec différentes bases de données. Le PDO ne va pas traduire vos requêtes SQL ou émuler les fonctionnalités manquantes, il ne gère que la connexion entre différents types de bases de données avec la même API.

Plus important encore, le PDO vous permet d'injecter en toute sécurité des entrées étrangères (par ex., les identifiants) dans vos requêtes SQL sans que vous ayez à vous soucier des attaques par injection SQL. Cela est rendu possible grâce à l'utilisation des fonctions de PDO et des paramètres liés.

Supposons qu'un script PHP reçoive un identifiant numérique en tant que paramètre d'entrée. Cet ID devrait être utilisé pour récupérer les enregistrements d'un utilisateur dans la base de données. Voici la mauvaise façon de s'y prendre :

1. <?php

2. $pdo = new PDO('sqlite:users.db');

3. $pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NON!

Ce code est mauvais. Vous insérez un paramètre en brut directement dans une requête SQL. C'est la porte ouverte pour le piratage comme l'injection SQL. Imaginez un instant que si un pirate envoie un paramètre id en invoquant l'URL http://domain.com/?id=1%3BDELETE+FROM+users. Cela va définir la variable $_GET['id'] à 1;DELETE FROM users ce qui va effacer l'ensemble de vos utilisateurs ! Au lieu de faire ça, vous devriez nettoyer les entrées en utilisant la liaison des paramètres avec PDO.

1. <?php

2. $pdo = new PDO('sqlite:users.db');

3. $stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');

4. $stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); // <-- Nettoyé automatiquement par PDO

5. $stmt->execute();

Voici le code correct. Il utilise un paramètre lié à une expression PDO. Cela « échappe » les entrées étrangères avant qu'elles ne soient introduites à la base de données ce qui empêche les attaques potentielles d'injection SQL.

En savoir plus sur PDO

Vous devriez savoir que les connexions à la base de données utilisent pas mal de ressources et il arrivait souvent que les ressources finissent par tarir si les connexions n'étaient pas implicitement fermées, cependant c'était plus souvent le cas dans les autres langages. En utilisant PDO, vous pouvez implicitement fermer la connexion en détruisant l'objet et en vous assurant que toutes les références à cet objet ont été supprimées, c'est-à-dire, mise à NULL. Si vous ne le faites pas explicitement, PHP va automatiquement fermer la connexion quand votre script s'arrêtera - à moins bien sûr, que vous n'utilisiez une connexion persistante.

En savoir plus sur les connexions avec PDO

VII-C - Couches d'abstractions

Beaucoup de frameworks fournissent leur propre couche d'abstraction qui peut être ou non basée sur PDO. Cette couche va souvent émuler les fonctionnalités d'une base de données qui seraient manquantes dans une autre base en enveloppant vos requêtes dans des méthodes PHP vous donnant ainsi une réelle abstraction avec la base de données. Cela engendre évidemment un léger surplus, mais si vous voulez développer une application portable ayant besoin de communiquer avec MySQL, PostgreSQL et SQLite alors ce petit surplus en vaudra la peine par souci de propreté et de maintenance du code.

Plusieurs couches d'abstractions ont été construites en utilisant les standards d'espace de noms PSR-0 ou PSR-4, ils peuvent donc être installés dans n'importe quelle application qui vous plaira :

- Aura SQL

- Doctrine2 DBAL

- Propel

- ZF2 Db

VII-D - Interagir avec les bases de données

Quand les développeurs commencent à utiliser PHP, ils finissent souvent par mélanger le code métier avec celui gérant la base de données et l'affichage ce qui donne quelque chose de ce genre-là :

1. <ul>

2. <?php

3. foreach ($db->query('SELECT * FROM table') as $row) {

4. echo "<li>".$row['field1']." - ".$row['field1']."</li>";

5. }

6. </ul>

Ceci est une mauvaise pratique pour toutes sortes de raisons, principalement dues au fait qu'il est plus difficile à déboguer, à lire et pour réaliser des tests.

Bien qu'il existe un certain nombre de solutions pour pallier ce problème comme l'utilisation de la POO ou bien la programmation fonctionnelle, les parties logiques de votre code doivent être clairement délimitées.

Considérez l'exemple suivant :

1. <?php

2. function getAllSomethings($db) {

3. return $db->query('SELECT * FROM table');

4. }

6. foreach (getAllFoos() as $row) {

7. echo "<li>".$row['field1']." - ".$row['field1']."</li>"; // MAUVAIS!!

8. }

C'est un bon début. La séparation entre l'interaction avec la base de données et l'affichage est déjà bien distincte.

Créez une classe où vous placerez les méthodes de votre code métier (votre « modèle »). Puis créez un fichier .php qui contient la logique d'affichage (votre « vue ») ce qui revient grosso modo à utiliser le pattern MVC - un modèle d'architecture très courant dans la plupart des frameworks.

foo.php

1. <?php

3. $db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

5. // Rendre votre modèle accessible

6. include 'models/FooModel.php';

8. // Création d'une instance

9. $fooList = new FooModel($db);

11. // Affichage du résultat

12. include 'views/foo-list.php';

models/FooModel.php

1. <?php

2. class Foo()

3. {

4. protected $db;

6. public function __construct(PDO $db)

7. {

8. $this->db = $db;

9. }

11. public function getAllFoos() {

12. return $this->db->query('SELECT * FROM table');

13. }

14. }

views/foo-list.php

1. <? foreach ($fooList as $row): ?>

2. <?= $row['field1'] ?> - <?= $row['field1'] ?>

3. <? endforeach ?>

C'est l'essentiel de ce que font les frameworks de façon plus manuelle. Vous n'avez pas forcément besoin de l'utiliser constamment, mais mélanger la présentation et la logique métier peut être un réel casse-tête si vous devez ensuite utiliser les tests unitaires dans votre application.

VIII - Templating

Les templates fournissent un moyen pratique de séparer les différentes préoccupations (contrôleur, logique, présentation). Les templates contiennent typiquement le HTML de votre application, mais ils peuvent aussi être utilisés avec d'autres formats comme le XML. Les templates sont souvent classés dans la catégorie « vues », le second composant du pattern MVC.

VIII-A - Bénéfices

L'intérêt principal d'utiliser les templates tient dans la séparation nette qui se crée entre la logique de présentation et le reste de l'application. Les templates sont seuls responsables de l'affichage du contenu formaté. Ils ne sont pas responsables de la récupération des données, ni de la persistance ou d'autres tâches complexes. Cela conduit à du code plus propre et plus lisible ce qui est particulièrement utile lorsque l'on travaille en équipe où l'on peut trouver à la fois des développeurs côté serveur (responsable de la partie « contrôleurs, modèles ») et les designers qui, eux, travaillent sur le code côté client.

Les templates améliorent aussi l'organisation du code pour l'affichage. Ils sont généralement placés dans un répertoire « views », chacun étant défini dans un seul fichier. Cette approche encourage la réutilisation de code où de larges blocs de code sont découpés de façon à obtenir un ensemble de briques « atomiques » et utilisables plus facilement. Par exemple, l'en-tête et le pied de page de votre site peuvent être définis dans des templates qui seront par la suite inclus respectivement au début et à la fin de chaque template d'une page.

Finalement, selon la bibliothèque que vous utilisez, les templates peuvent vous offrir plus de sécurité en échappant par exemple automatiquement les variables définies par les entrées d'un utilisateur. Quelques bibliothèques vous offrent même la possibilité d'isoler les variables et les fonctions (on parlera de « sand-boxing ») définies dans une liste blanche de façon, par ex., à limiter les dégâts collatéraux provoqués par une mauvaise utilisation faite par les designers.

VIII-B - Templates en PHP « pur »

Les templates « pur PHP » sont ceux qui n'utilisent que du code PHP natif. C'est un choix naturel étant donné que PHP est lui-même un langage de templating. Ce terme signifie tout simplement que vous pouvez combiner du code PHP avec un autre langage comme le HTML. Cela peut être considéré comme un atout du fait même que les développeurs n'ont pas à apprendre une syntaxe particulière. Par ailleurs, ces templates tendent à être plus rapides étant donné qu'il n'y a pas de phase de compilation.

Tous les frameworks PHP modernes utilisent un système de templating, la plupart se basant uniquement sur la syntaxe PHP. En dehors des frameworks, des bibliothèques comme Plates ou Aura.View rendent le travail avec les templates en PHP « pur » plus facile en offrant des fonctionnalités « modernes » telles que l'héritage, le layout et des extensions.

Exemple d'un template en PHP « pur » (utilisant Plates) :

1. <?php $this->insert('header', ['title' => 'Profil utilisateur']) ?>

3. <h1>Profil utilisateur</h1>

4. <p>Bonjour, <?=$this->escape($name)?></p>

6. <?php $this->insert('footer') ?>

VIII-C - Templates compilés

Bien que le PHP ait évolué en un langage orienté objet mature, il ne s'est pas énormément amélioré en tant que langage de templating. Les templates compilés comme Twig ou Smarty remplissent ce vide en offrant une nouvelle syntaxe, adaptée aux exigences des applications modernes. Cela va de l'échappement automatique à l'héritage en passant par des structures de contrôles simplifiées. Ces templates ont été conçus dans l'idée de faciliter l'écriture, la sécurité et la maintenance du code gérant la partie visuelle de l'application. Les templates compilés peuvent même être partagés entre différents langages, Mustache étant un bon exemple de cela. Étant donné que ces templates doivent être compilés, il y a une légère baisse de performances. Cependant, cela peut être anecdotique si un système de cache approprié est utilisé.

Exemple d'un template compilé (utilisant Twig) :

1. {% include 'header.html' with {'title': 'Profil utilisateur'} %}

3. <h1>Profil utilisateur</h1>

4. <p>Bonjour, {{ name }}</p>

6. {% include 'footer.html' %}

IX - Les erreurs et exceptions

IX-A - Erreurs

Le PHP a plusieurs niveaux de gravité pour les erreurs. Les trois types de messages d'erreurs les plus communs sont les erreurs, les avertissements et les remarques. Il existe différents niveaux de gravité : E_ERROR, E_WARNING et E_NOTICE. Les erreurs sont des erreurs d'exécution fatales et sont souvent causées par des bogues qui ont besoin d'être réglés étant donné qu'ils stoppent l'interprétation du reste du code. Les avertissements sont des erreurs non fatales, autrement dit l'exécution du script continuera. Les remarques sont des messages informatifs sur du code qui pourrait poser problème lors de l'exécution du script, cependant l'exécution ne sera pas arrêtée.

Il existe un autre type de message d'erreur qui se présente lors de la phase de compilation, c'est le message E_STRICT. Ces messages sont utilisés pour suggérer des changements dans votre code afin de s'assurer de la meilleure interopérabilité et de la meilleure compatibilité ascendante possible.

Constantes prédéfinies pour la gestion des erreurs

IX-B - Exceptions

Les exceptions sont une partie standardisée dans la plupart des langages de programmation populaires, mais elles sont souvent négligées par les programmeurs PHP. Les langages comme Ruby sont très fortement équipés pour gérer les exceptions ainsi, à chaque fois qu'une chose se passe mal comme l'échec d'une requête HTTP ou d'une requête à la BDD, Ruby (ou les « gems » utilisés) va lancer une exception à l'écran vous indiquant immédiatement qu'il y a eu une erreur.

Le PHP en lui-même est plutôt laxiste avec ce type d'erreur, ainsi un appel à file_get_contents() va généralement renvoyer un FALSE accompagné d'un avertissement. Beaucoup d'anciens frameworks PHP comme CodeIgniter vont juste retourner false, enregistrer un message dans leur fichier de log et peut-être vous laisser utiliser une méthode comme $this->upload->get_error() pour voir ce qu'il s'est mal passé. Le problème ici est que vous devez vous-même chercher l'erreur et vérifier dans la doc ce qu'elle signifie pour cette fonction au lieu de l'avoir rendue évidente à comprendre.

L'autre problème arrive lorsque les classes lancent automatiquement une erreur à l'écran et termine le processus. Si vous faites cela, un autre développeur ne sera plus capable de gérer cette erreur à l'exécution. Les exceptions devraient être lancées afin d'avertir le développeur qu'une chose ne s'est pas passée comme prévu, ça devrait être à eux de décider comment ils veulent gérer cela, par exemple :

1. <?php

2. $email = new Fuel\Email;

3. $email->subject('Mon sujet');

4. $email->body('Comment allez-vous ?');

5. $email->to('guy@exemple.com', 'Un gars');

7. try

8. {

9. $email->send();

10. }

11. catch(Fuel\Email\ValidationFailedException $e)

12. {

13. // La validation a échoué

14. }

15. catch(Fuel\Email\SendingFailedException $e)

16. {

17. // Le pilote ne peut pas envoyer l'email

18. }

19. finally

20. {

21. // ce bloc est exécuté même si une exception a été générée et avant que l'exécution normale reprenne

22. }

IX-B-1 - Les exceptions SPL

La classe générique Exception ne fournit pas un contexte intéressant pour le débogage. Pour remédier à cela, il est possible de créer une sous-classe du type générique Exception :

1. <?php

2. class ValidationException extends Exception {}

Cela vous permet d'ajouter plusieurs blocs catch et de gérer les exceptions différemment. Cela peut conduire à la création de beaucoup de classes personnalisées qui auraient pu être évitées si les exceptions de la SPL avaient été utilisées avec l'extension SPL.

Si par exemple vous utilisez la méthode magique __call() et qu'une méthode invalide est demandée alors, au lieu de générer une exception standard vague ou d'utiliser une sous-classe personnalisée, vous pourriez tout simplement faire throw new BadFunctionCallException.

X - Sécurité

X-A - La sécurité dans une application web

De nombreuses personnes mal intentionnées tenteront d'exploiter les possibles failles dans votre application web. Il est important que vous ayez conscience de cela et que vous preniez les précautions nécessaires afin de renforcer la sécurité dans votre application. Heureusement, les gens du projet « Open Web Application Security » (OWASP en anglais) ont compilé une liste exhaustive des principaux problèmes de sécurité connus et les méthodes pour vous en prémunir. C'est une lecture indispensable pour tout développeur consciencieux de la sécurité.

Lire le guide de sécurité OWASP

X-B - Hachage de mots de passe

Pratiquement tout le monde construit une application PHP qui se base sur une authentification de l'utilisateur. Les identifiants et les mots de passe sont stockés dans une base de données et utilisés plus tard pour authentifier les utilisateurs.

Il est important que vous utilisiez correctement les fonctions de hachage avant de les stocker. Le hachage de mots de passe est une opération irréversible produisant une chaîne de caractères de longueur fixe. Cela signifie que vous pouvez comparer le produit d'une fonction de hachage avec le hash stocké en base de données pour déterminer s'il s'agit du même texte. Si les mots de passe stockés en base de données ne sont pas « hachés », alors n'importe qui ayant accès à cette base peut compromettre les comptes utilisateurs. Il arrive souvent que les utilisateurs utilisent le même mot de passe pour d'autres services, c'est pourquoi il faut prendre la sécurité des informations avec sérieux.

Hachage de mots de passe avec password_hash

La fonction password_hash a été introduite avec la version 5.5 de PHP. À l'heure actuelle, elle utilise BCrypt qui est l'algorithme le plus robuste. Cela va être mis à jour dans le futur afin de supporter plus d'algorithmes. La bibliothèque password_compat a été créée afin de fournir une compatibilité ascendante avec PHP >= 5.3.7.

Dans l'exemple ci-dessous, nous hachons une chaîne de caractères et faisons une vérification sur une chaîne différente. Étant donné que les deux chaînes sont différentes (‘secret-password' vs. ‘bad-password'), l'authentification va échouer.

1. <?php

3. require 'password.php';

5. $passwordHash = password_hash('secret-password', PASSWORD_DEFAULT);

7. if (password_verify('bad-password', $passwordHash)) {

8. // Mot de passe correct

9. } else {

10. // Mauvais mot de passe

11. }

X-C - Filtrage des données

Une règle d'or : ne jamais faire confiance aux entrées extérieures dans votre code PHP. Prenez toujours soin de « nettoyer » et de valider ces entrées avant de les utiliser dans le code. Les fonctions filter_var et filter_input peuvent nettoyer les entrées textuelles et valider les données comme les emails.

Les entrées étrangères viennent de n'importe où : les données de formulaire envoyées via $_GET ou $_POST, des valeurs dans la variable superglobales $_SERVER et le corps des requêtes HTTP via fopen('php://input', 'r'). N'oubliez pas, les entrées étrangères ne se limitent pas aux données envoyées par l'utilisateur. Les fichiers uploadés et téléchargés, les valeurs de session, les données des cookies et les données provenant de services tiers sont aussi des entrées étrangères.

Demandez-vous à chaque fois que vous traitez, affichez, concaténez ou incluez des données dans votre code si ces données ont été correctement filtrées et qu'elles peuvent être considérées comme sures.

Les données peuvent être filtrées différemment selon le contexte. Par exemple, quand des données brutes sont envoyées en sortie vers la page HTML, elles peuvent exécuter du JavaScript et du HTML. Cette technique est connue sous le nom de « Cross-Site Scripting » (XSS) et peut se révéler très dangereuse. Une façon d'éviter les attaques XSS est de nettoyer toutes les données générées par l'utilisateur avant de les afficher sur votre page en retirant toutes balises HTML avec la fonction strip_tags ou en échappant les caractères spéciaux tels que ‘<' ou ‘>' avec les fonctions htmlentities ou htmlspecialchars.

Un autre exemple est lorsque l'on passe des options à exécuter en ligne de commandes. Cela peut être très dangereux (et est souvent une mauvaise idée), mais vous pouvez utiliser la fonction escapeshellarg pour nettoyer les arguments d'une commande.

Un dernier exemple concerne le fait d'autoriser les entrées étrangères pour déterminer le fichier à télécharger depuis le système de fichiers. Cela peut être exploité en changeant le chemin vers le fichier. Vous devez supprimer « / », « ../ », les octets null ou d'autres caractères du chemin de façon à empêcher le chargement de fichiers cachés, privés ou contenant des données sensibles.

- En savoir plus sur le filtrage des données

- En savoir plus sur

- En savoir plus sur

- En savoir plus sur la gestion des octets null

X-C-1 - Nettoyage

Le « nettoyage » supprime (ou échappe) les caractères illégaux ou considérés comme dangereux.

Par exemple, vous devriez nettoyer les entrées étrangères avant d'inclure les entrées en HTML ou de les insérer dans une requête SQL. Si vous utilisez les paramètres liés avec PDO, il nettoiera les entrées pour vous.

Parfois il est nécessaire d'autoriser certains tags HTML dans les entrées quand on les inclut dans la page HTML. Cela se révèle souvent très compliqué à mettre en œuvre et beaucoup l'évite, c'est pourquoi il existe des syntaxes de formatage telles que Markdown or BBCode bien que des bibliothèques comme HTML Purifier vous permettent d'intégrer directement du HTML. Voir les filtres de nettoyage

X-C-2 - Validation

La validation s'assure que les entrées extérieures correspondent à ce que vous vous attendiez. Par exemple, vous pourriez vouloir valider une adresse email, un numéro de téléphone ou un âge lors du traitement de l'enregistrement d'un compte.

Voir les filtres de validation

X-D - Fichiers de configuration

Lorsque vous créez des fichiers de configuration pour vos applications, les meilleures pratiques recommandent que les méthodes ci-dessous soient suivies :

- il est recommandé que vous stockiez vos informations de configuration là où aucun utilisateur non autorisé ne peut y accéder (via le système de fichier) ;

- si vous devez stocker vos fichiers de configuration à la racine du projet, nommer les fichiers avec l'extension .php. Cela permet de s'assurer que même si le fichier est accédé directement, il ne s'affichera pas en texte brut ;

- les informations contenues dans les fichiers de configuration doivent être protégées correctement, que ce soit via le chiffrage et/ou via le système de permissions des utilisateurs/groupes du système de fichiers.

X-E - Register Globals

** NOTE : ** Depuis la version 5.4.0 de PHP, le paramètre register_globals a été retiré et ne peut plus être utilisé. Les applications plus anciennes n'afficheront plus qu'un avertissement si ce paramètre est utilisé.

Quand il est activé, le paramètre de configuration register_globals permet à plusieurs types de variables (cela inclut notamment les paramètres $_POST, $_GET and $_REQUEST) d'être accessibles partout dans votre application. Cela peut facilement conduire à des problèmes de sécurité étant donné que votre application ne peut de façon claire dire d'où proviennent les données.

Par exemple: $_GET['foo'] sera accessible via $foo ce qui peut écraser des variables non encore déclarées. Si vous utilisez PHP < 5.4.0 assurez-vous que ce paramètre est à off.

Register_globals dans le manuel PHP

X-F - Rapport d'erreurs

La journalisation des erreurs peut être utile pour repérer les points qui posent problème dans votre application, mais cela permet aussi d'afficher des informations sur la structure de votre application au monde extérieur. Pour vous protéger efficacement contre ce genre de problèmes, vous avez besoin de configurer votre serveur différemment entre la version de développement et celle pour la production.

X-F-1 - Développement

Pour afficher toutes les erreurs possibles durant le développement, configurez les paramètres suivants dans votre fichier php.ini :

1. display_errors = On

2. display_startup_errors = On

3. error_reporting = -1

4. log_errors = On

En passant la valeur -1, toutes les erreurs possibles seront affichées, même lors de l'ajout d'autres niveaux et constantes dans les futures versions de PHP. La constante E_ALL fonctionne de la même façon depuis PHP 5.4. - php.net

Le niveau d'erreur E_STRICT a été introduit avec PHP 5.3.0 et ne fait pas partie de E_ALL, cependant il est dorénavant inclus dans E_ALL depuis la 5.4.0. Pour pouvoir rapporter toutes les erreurs en 5.3, il est donc nécessaire d'utiliser soit -1 ou E_ALL | E_STRICT.

Rapporter toutes les erreurs possibles par version PHP

- < 5.3 -1 ou E_ALL

- 5.3 -1 ou E_ALL | E_STRICT

- > 5.3 -1 ou E_ALL

X-F-2 - Production

Pour cacher l'affichage d'erreurs dans votre environnement de production, configurez votre fichier php.ini de cette façon :

1. display_errors = Off

2. display_startup_errors = Off

3. error_reporting = E_ALL

4. log_errors = On

Avec ces paramètres, les erreurs seront toujours enregistrées dans les journaux d'erreurs de votre serveur web, mais ne seront pas affichées à l'utilisateur. Pour plus d'informations sur ces paramètres, voir le manuel PHP:

- error_reporting

- display_errors

- display_startup_errors

- log_errors

XI - Tests

Écrire des tests automatisés pour votre code PHP est considéré comme une très bonne pratique et permet de construire des applications plus robustes. Les tests automatisés sont un excellent outil pour s'assurer que votre application fonctionne toujours (lorsque vous faites des changements ou quand vous ajoutez de nouvelles fonctionnalités) et ne devraient pas être ignorés.

Il existe différents types d'outils de test (ou framework) disponibles pour PHP qui utilisent différentes approches - tous tentent d'éviter les tests manuels et le besoin d'un socle pour l'équipe chargée de faire l'assurance qualité (QA), s'assurant ainsi que les récents changements ne viendront pas casser l'existant.

XI-A - Développement dirigé par les tests (TDD)

Le Test Driven Development (TDD) ou en français développement piloté par les tests est une technique de développement de logiciels qui préconise d'écrire les tests unitaires avant d'écrire le code source d'un logiciel.

XI-A-1 - Test unitaire

Le test unitaire est une approche dans la programmation qui s'assure que les fonctions, les classes et les méthodes écrites fonctionnent comme prévu tout le long du cycle de développement. En vérifiant les valeurs en entrée et en sortie des différentes fonctions, vous vous assurez du bon fonctionnement de la logique interne. En utilisant l'injection de dépendances et en construisant des classes mocks et des classes stubs, vous pouvez vérifier que les dépendances sont correctement utilisées pour une meilleure couverture du code.

Quand vous créez une classe ou une fonction, vous devriez aussi créer un test unitaire couvrant l'ensemble des états possibles. À un niveau très basique, vous devriez vous assurer que les changements effectués sur une fonction ou une classe ne modifieront pas le comportement attendu de l'application. La seule autre possibilité pour les tests unitaires serait l'utilisation de la fonction var_dump() ce qui n'est pas viable que ce soit pour une petite ou une grande application.

L'autre cas d'utilisation des tests unitaires est la contribution à la communauté open source. Vous pouvez ainsi écrire un test montrant une fonctionnalité boguée puis la réparer en montrant cette fois qu'elle passe le test. Les patches auront plus de chances d'être acceptés de cette manière. Si vous travaillez sur un projet acceptant les « pull requests » alors vous devriez exiger un (ou plusieurs) test avant chaque patch.

PHPUnit est le framework de test standard (de facto) pour écrire des tests unitaires pour des applications PHP, mais il existe d'autres solutions :

- atoum ;

- Enhance PHP ;

- PUnit ;

- SimpleTest.

XI-A-2 - Test d'intégration

Un test d'intégration est un test qui se déroule dans une phase d'un projet informatique suivant les tests unitaires. Il consiste, une fois que les développeurs ont chacun validé leurs développements ou leurs correctifs, à regrouper leurs modifications ensemble dans le cadre d'une livraison.

Beaucoup des outils utilisés pour les tests unitaires peuvent aussi l'être pour les tests d'intégration étant donné qu'ils partagent les mêmes principes.

XI-A-3 - Test fonctionnel

Les tests fonctionnels servent à vérifier que chaque fonction est correctement implémentée, c'est-à-dire conforme aux exigences et aux spécifications. On vérifie chaque fonction indépendamment les unes des autres, généralement en termes d'entrées/sorties.

Une autre variante connue est le test d'acceptation qui lui vérifie que le produit répond aux attentes de l'utilisateur, c'est-à-dire qu'il est conforme aux besoins et au cahier des charges. On vérifie le produit dans son ensemble, généralement avec des scénarios réalistes d'utilisation.

XI-A-4 - Outils pour les tests fonctionnels

- Selenium

- Mink

- Codeception est un framework de test complet incluant aussi des outils pour les tests d'acceptation

- Storyplayer est un framework de test complet qui inclut un support pour créer et détruire des environnements de test à la demande

XI-B - Behavior Driven Development

Il existe deux types de développement orienté comportement (BDD en anglais) : SpecBDD et StoryBDD. SpecBDD se concentre les aspects techniques du code alors que StoryBDD lui se concentre sur la partie métier, les fonctionnalités apportées ou bien encore les interactions. Le PHP possède des frameworks pour ces types de BDD.

Avec StoryBDD, vous écrivez des histoires « humainement » lisibles qui décrivent le comportement de votre application. Ces histoires peuvent ensuite être transformées en tests se lançant sur votre application. Le framework utilisé dans les applications PHP pour StoryBDD est Behat qui s'inspire de Cucumber pour Ruby et implémente le langage Gherkin DSL pour décrire les fonctionnalités.

Avec SpecBDD, vous écrivez des spécifications décrivant comment votre code devrait se comporter. Au lieu de tester une fonction ou une méthode, vous décrivez comment cette fonction ou méthode devrait s'exécuter. Pour atteindre ce but, il existe un framework qui s'appelle PHPSpec. Ce framework s'inspire lui aussi d'un projet Ruby, Rspec.

XI-B-1 - Liens sur le BDD

- Behat, le framework StoryBDD pour PHP, inspiré de Cucumber;

- PHPSpec, le framework SpecBDD pour PHP, inspiré de RSpec;

- Codeception est un framework de test complet utilisant les principes du BDD.

XI-C - Outils de test complémentaire

Hormis les tests unitaires et les frameworks orientés comportement, il y a aussi un certain nombre de frameworks génériques et de bibliothèque utilitaires selon l'approche désirée.

XI-C-1 - Liens vers les outils

- Selenium est un outil d'automatisation d'utilisation d'un navigateur web qui peut être intégré à PHPUnit.

- Mockery est un framework de Mock qui peut être intégré avec PHPUnit ou PHPSpec.

- Prophecy est un framework de Mock très puissant et flexible. Il est intégré à PHPSpec et peut être utilisé avec PHPUnit.

XII - Les serveurs et le déploiement

Les applications PHP peuvent être déployées et exécutées sur les serveurs de production de diverses manières.

XII-A - Platform as a Service (PaaS)

Les PaaS fournissent l'architecture système et réseau nécessaire pour faire tourner une application PHP sur le web. Cela signifie qu'il n'y a pratiquement aucune configuration requise pour lancer des applications ou des frameworks PHP.

Les PaaS sont devenues récemment une méthode populaire pour déployer, héberger et monter en puissance (notion de « scalabilité ») des applications PHP de toutes tailles. Vous pouvez trouver une liste de fournisseurs de PaaS PHP dans la section ressources.

XII-B - Serveurs virtuels et dédiés

Si vous vous sentez à l'aise avec l'administration des systèmes ou êtes intéressé pour en connaître plus sur ce domaine, les serveurs virtuels et dédiés vous donnent un contrôle absolu sur l'environnement de production de votre application.

XII-B-1 - nginx et PHP-FPM

PHP via le gestionnaire de processus intégré FastCGI (FPM en anglais) s'accorde très bien avec nginx qui est un serveur web léger et hautement performant. Il utilise moins de mémoire qu'Apache et gère mieux les requêtes faites en parallèle. Cela est spécialement important pour les serveurs virtuels manquant de mémoire.

- En savoir plus sur nginx

- En savoir plus sur PHP-FPM

- En savoir plus sur la configuration de nginx et PHP-FPM

XII-B-2 - Apache et PHP

PHP et Apache ont une longue histoire commune. Apache est très largement configurable et un très grand nombre de modules sont disponibles pour étendre ses fonctionnalités. C'est un choix populaire pour les serveurs mutualisés, car il est très simple pour des frameworks PHP comme Wordpress de s'installer dessus. Malheureusement, Apache utilise plus de ressources que nginx par défaut et ne peut gérer qu'un nombre limité de clients à la fois.

Apache possède différentes configurations possibles pour faire tourner PHP. La plus commune et la plus facile est d'installer le prefork MPM avec le module mod_php5. Bien qu'il ne soit pas le plus efficace en termes de gestion de la mémoire, il est le plus simple à lancer et utiliser. C'est probablement le meilleur choix si vous ne souhaitez pas vous plonger dans les aspects trop techniques de l'administration d'un serveur. Notez que si vous utilisez mod_php5, vous DEVEZ utiliser le prefork MPM.

Alternativement, si vous voulez profiter de plus de perfomances et de stabilité avec Apache alors vous pouvez tirer avantage à utiliser le même FPM que nginx et faire tourner le worker MPM ou l'event MPM avec mod_fastcgi ou mod_fcgid. Cette configuration sera nettement meilleure en termes d'utilisation mémoire et plus rapide, mais cela demandera plus de travail pour le mettre en place.

- En savoir plus sur Apache

- En savoir plus sur les modules MultiProcessing

- En savoir plus sur mod_fastcgi

- En savoir plus sur mod_fcgid

XII-C - Hébergement mutualisé

Grâce à la popularité de PHP, il existe de nombreuses solutions d'hébergements mutualisés. Il est difficile d'ailleurs de trouver un hébergeur qui ne propose pas l'installation de PHP, mais vérifiez tout de même que ce soit la dernière version qui est installée. Les hébergements mutualisés vous permettent à vous et à d'autres développeurs de déployer des sites sur une seule machine. L'avantage est que cela est une solution économique. L'inconvénient est que vous ne savez jamais quel genre de grabuge vos « voisins » peuvent faire : ralentir le serveur ou laisser des failles de sécurité sont les principaux problèmes. Si votre budget le permet, évitez d'utiliser cette solution.

XII-D - Constuire et déployer votre application

Si vous vous retrouvez à faire des changements sur le schéma de la base de données vous-même ou que vous exécutez vos tests manuellement avant de mettre à jour vos fichiers (là aussi manuellement), vous devriez sans doute repenser votre méthodologie de développement! Avec l'ensemble des étapes manuelles que vous devez réaliser pour déployer une nouvelle version de votre application, il y a de fortes chances pour que des erreurs potentiellement fatales viennent se glisser durant l'une des étapes. Que ce soit une simple mise à jour, un processus de construction et de déploiement, voire une stratégie d'intégration continue, le moteur de production est votre ami.

Parmi les tâches que vous pourriez vouloir automatiser, vous trouverez :

- le gestionnaire de dépendances ;

- la compilation, la minification de vos ressources ;

- l'exécution des tests ;

- la création de la documentation ;

- le « packaging » ;

- le déploiement.

XII-D-1 - Outil de construction automatique

Les outils de construction automatique (« build tools » en anglais) peuvent être souvent vus comme un ensemble de scripts gérant les tâches les plus répétitives pour le déploiement d'un logiciel. Il ne fait généralement pas partie du logiciel en lui-même, agissant ainsi depuis l'extérieur.

Il existe beaucoup d'outils open source disponibles pour vous aider à automatiser la construction de votre application, certains étant même écrits en PHP. Cela ne devrait pas vous empêcher de les utiliser, si jamais ils correspondent mieux au travail demandé. Voici quelques exemples :

Phing est le moyen le plus facile pour commencer à utiliser le déploiement automatisé avec PHP. Avec Phing, vous pouvez contrôler les processus de « packaging », de déploiement et d'exécution de tests à l'aide d'un simple fichier XML. Phing (qui est basé sur Apache Ant) fournit un riche ensemble de tâches généralement nécessaire pour installer ou mettre à jour une application web et peut être amélioré avec l'ajout de tâches personnalisées, écrit en PHP ;

Capistrano est un système pour les programmeurs de niveau intermédiaire à avancer pour exécuter des commandes de façon structurée et répétable sur une ou plusieurs machines distantes. Il est préconfiguré pour déployer des applications Ruby On Rails, cependant nombreux sont ceux à l'utiliser pour déployer avec succès des applications PHP. La bonne utilisation de Capistrano dépend de vos connaissances en Ruby et Rake.

Le post du blog de Dave Gardner sur le déploiement PHP avec Capistrano est un bon point de départ pour les développeurs qui seraient intéressés ;

Chef est plus qu'un framework de déploiement basé sur Ruby, car il peut aussi générer l'ensemble de l'environnement de votre serveur ou de votre machine virtuelle.

XII-D-2 - Intégration continue

L'intégration continue est une pratique en génie logiciel où les membres d'une équipe intègrent leurs travaux fréquemment, souvent plusieurs fois par jour. Beaucoup d'équipes trouvent que cette approche permet de réduire de façon significative les problèmes d'intégration et ainsi permet un développement plus cohérent et rapide. - Martin Fowler

Il existe différents moyens pour faire de l'intégration continue en PHP. Travis CI a récemment fait un excellent travail pour faire de l'intégration continue une réalité, et ce, même pour de petits projets. Travis CI est un service hébergé d'intégration continue pour la communauté open source. Il est intégré à Github et offre un support de haut niveau pour de nombreux langages (incluant PHP).

XIII - Cache

Le PHP est plutôt rapide en lui-même, mais certains points de congestion peuvent apparaître quand vous établissez des connexions distantes, des chargements de fichiers, etc. Heureusement, il y a de nombreux outils disponibles pour accélérer certaines parties de vos applications ou pour réduire le nombre de fois où ces actions consommatrices de temps ont besoin de se lancer.

XIII-A - Cache du bytecode

Quand un fichier PHP est exécuté, il est d'abord compilé sous forme de bytecode (aussi connu sous le nom d'opcode) puis ce bytecode est ensuite exécuté. Si le fichier PHP n'est pas modifié, le bytecode restera toujours le même ce qui signifie que sa compilation lors de chaque appel sera une perte de ressources CPU.

C'est là que le cache du bytecode intervient. Il empêche la compilation récurrente en stockant le bytecode en mémoire et en le réutilisant à chaque appel successif. Mettre en place le cache ne prend que quelques minutes, mais cela
augmentera de façon significative la réactivité de votre application. Il n'y a donc aucune raison de ne pas l'utiliser.

Avec PHP 5.5, il existe un cache intégré pour le bytecode appelé OPcache. Il est aussi disponible pour les versions précédentes.

Les autres caches pour bytecode sont :

- APC (PHP 5.4 et antérieur) ;

- XCache ;

- Zend Optimizer+ (fait parti de Zend Server) ;

- WinCache (extension pour MS Windows Server).

XIII-B - Cache des objets

Il arrive parfois qu'il soit plus avantageux de mettre en cache des objets individuels dans votre code par exemple dans les cas où l'on souhaite récupérer le même résultat provenant d'une base de données. Vous pouvez utiliser des logiciels de cache objet pour maintenir ces bouts de données en mémoire pour un usage ultérieur. Si vous enregistrez ces éléments en mémoire après les avoir récupérés, vous pouvez considérablement gagner en rapidité d'accès, de même qu'une réduction de l'utilisation de la base de données.

Beaucoup des solutions de cache du bytecode vous permettent de mettre aussi en cache les données, il y a donc encore plus d'avantages à les utiliser. APCu, XCache, et WinCache fournissent tous des API pour stocker les données de votre code PHP dans leur système de cache mémoire.

Les systèmes de cache objet les plus courants sont APCu and memcached. APCu est un excellent choix en ce qui concerne le cache objet, il inclut une API simple pour ajouter vos propres données dans son cache et est très facile à configurer. La seule vraie limitation d'APCu est qu'il est lié au serveur où il est installé. Memcached, d'un autre côté, s'installe de façon séparée en tant que service et peut être accédé depuis le réseau ce qui signifie que vous pouvez stocker les objets dans un unique endroit même s'ils proviennent de systèmes différents.

Notez que lorsque PHP s'exécute en tant qu'application (Fast)-CGI au sein de votre serveur, les processus PHP auront leur propre cache, c'est-à-dire que les données d'APCu ne seront pas partagées entre les différents processus. Dans ce cas, vous pourriez envisager d'utiliser memcached étant donné qu'il n'est pas lié aux processus PHP.

Dans une configuration réseau, APCu va généralement surpasser memcached en termes de rapidité d'accès, mais memcached sera capable d'être « scalable » plus rapidement et de façon plus poussée. Si vous ne vous attendez pas à avoir plusieurs serveurs pour gérer votre application, ou si vous ne souhaitez pas utiliser les fonctionnalités spécifiques de memcached alors APCu est probablement votre meilleur choix pour le cache d'objets.

Exemple utilisant APCu :

1. <?php

2. // vérifie si la variable 'expensive_data' existe dans le cache

3. $data = apc_fetch('expensive_data');

4. if ($data === false) {

5. // la donnée n'est pas en cache; enregistrer le résultat de l'appel d'une fonction longue pour plus tard

6. apc_add('expensive_data', $data = get_expensive_data());

7. }

9. print_r($data) ;

Remarque : Avant PHP 5.5, l'APC fournit à la fois un cache d'objet et un cache pour le bytecode. l'APCu est un projet visant à apporter le cache d'objet à PHP 5.5+ depuis que PHP a un cache de bytecode intégré (OPcache).

En savoir plus sur les systèmes de cache objets les plus connus :

- APCu ;

- Fonctions APC ;

- Memcached ;

- Redis ;

- API XCache ;

- Fonctions WinCache.

XIV - Documentation du code

XIV-A - PHPDoc

PHPDoc est un standard informel pour commenter du code PHP. Il existe un grand nombre de tags disponibles. La liste complète des tags et des exemples peuvent être trouvés sur le manuel PHPDoc.

Vous trouverez ci-dessous un exemple d'utilisation des principaux tags :

1. <?php

2. /**

3. * @author Votre nom <nom@exemple.com>

4. * @link http://www.phpdoc.org/docs/latest/index.html

5. * @package helper

6. */

7. class DateTimeHelper

8. {

9. /**

10. * @param mixed $anything Tout ce qui peut être traduit en un objet \DateTime

11. *

12. * @return \DateTime

13. * @throws \InvalidArgumentException

14. */

15. public function dateTimeFromAnything($anything)

16. {

17. $type = gettype($anything);

19. switch ($type) {

20. // Ce bloc doit retourner un objet \DateTime

21. }

23. throw new \InvalidArgumentException(

24. "Impossible de convertir '{$type}' en un objet DateTime"

25. );

26. }

28. /**

29. * @param mixed $date Tout ce qui peut être traduit en un objet \DateTime

30. *

31. * @return void

32. */

33. public function printISO8601Date($date)

34. {

35. echo $this->dateTimeFromAnything($date)->format('c');

36. }

38. /**

39. * @param mixed $date Tout ce qui peut être traduit en un objet \DateTime

40. */

41. public function printRFC2822Date($date)

42. {

43. echo $this->dateTimeFromAnything($date)->format('r');

44. }

45. }

La documentation d'une classe commence en premier lieu par l'introduction du nom de l'auteur avec le tag @author qui peut être répété s'il y a plusieurs auteurs. En deuxième lieu, nous pouvons indiquer un lien vers un site web si jamais il existe une relation entre ce dernier et le code via le tag @link. Enfin, si jamais la classe fait partie d'un espace de noms, il faut l'indiquer avec le tag @package.

À l'intérieur de cette classe, la première méthode a un paramètre indiqué par @param qui nous renseigne sur son type, son nom et une brève description. Si jamais une méthode renvoie un résultat, il faut l'indiquer avec le tag @return et utilisez @throws autant de fois qu'il y a d'exceptions signalées.

La seconde et la troisième méthodes sont très similaires et ont un unique tag @param comme la première méthode. La seule différence notable se trouvant dans la doc. est la présence d'un tag @return sur la seconde méthode. La valeur void pour le tag @return nous informe explicitement que la méthode ne renvoie rien (si vous omettez ce tag, c'est cette valeur qui sera indiquée par défaut).

N.D.T. À noter que void n'est pas un type valide pour PHP, c'est pourquoi je préconise de mettre plutôt la valeur null qui est celle retournée par défaut quand la fonction ne contient pas d'instruction return.

XV - Ressources

XV-A - Officielles

- Site web PHP

- Documentation PHP

XV-B - Mentorat

- phpmentoring.org - Encadrement et montée en compétences par des membres de la communauté

XV-C - Fournisseurs PaaS pour PHP

- PagodaBox

- AppFog

- Heroku (Le support pour PHP n'est pas documenté, mais est basé sur le partenariat
avec Facebook : lien)

- fortrabbit

- Engine Yard Cloud

- Red Hat OpenShift Platform

- dotCloud

- AWS Elastic Beanstalk

- cloudControl

- Windows Azure

- Zend Developer Cloud

- Google App Engine

- Jelastic

XV-D - Frameworks

Plutôt que de réinventer la roue, beaucoup de développeurs PHP utilisent des frameworks pour construire leur application web. Les frameworks permettent de s'abstraire des préoccupations de bas niveau et fournissent de précieuses interfaces pour remplir les tâches les plus communes.

Vous n'avez pas besoin d'utiliser un framework pour chacun de vos projets. Parfois, du PHP brut est le meilleur choix, mais si vous avez besoin d'un framework alors il en existe de trois sortes :

- les microframeworks ;

- les frameworks complets (« full-stack » en anglais) ;

- les frameworks orientés composant.

Les microframeworks sont essentiellement des surcouches pour router une requête HTTP vers une fonction de rappel (callback en anglais), une méthode, etc. de façon aussi rapide que possible et parfois sont accompagnés de quelques bibliothèques supplémentaires pour vous assister dans le développement telles qu'une surcouche pour la gestion d'une base de données, etc. Ils sont principalement utilisés pour construire des services HTTP distants.

Beaucoup de frameworks ajoutent un nombre considérable de fonctionnalités au-dessus de ce qui est disponible dans un microframework et ceux-ci sont appelés « framework full-stack ». Ils sont souvent fournis avec des ORM, des packages d'authentification, etc.

Les frameworks orientés composant sont des collections de bibliothèques spécialisées. Plusieurs de ces frameworks peuvent être utilisés ensemble pour former un micro ou un framework complet.

Frameworks PHP populaires

XV-E - Composants

Comme mentionné au-dessus, les « composants » sont une autre approche pour atteindre l'objectif de créer, distribuer et implémenter du code partagé. Différents dépôts de composants existent, les deux plus connus sont :

- Packagist ;

- PEAR.

Chacun de ces deux dépôts possède des outils en ligne de commande qui lui sont associés afin d'installer et de mettre à jour les processus, ce qui est expliqué plus en détail dans la section gestion des dépendances.

Il existe aussi des frameworks basés sur les composants qui vous permettent d'utiliser leurs composants avec (ou sans) conditions requises. Par exemple, vous pouvez utiliser le package pour la validation de FuelPHP sans l'obligation d'utiliser le framework tout entier. Ces projets sont essentiellement juste d'autres répertoires pour la réutilisation de composants :

- Aura ;

- FuelPHP (2.0 seulement) ;

- « Illuminate Components »de Laravel ;

- Composants Symfony.

XV-F - Livres

Il existe un grand nombre de livres autour du PHP, mais un certain nombre sont malheureusement obsolètes et ne contiennent plus d'informations à jour. Il existe même des livres publiés pour « PHP 6 » qui n'a pas encore vu le jour (et qui ne le sera probablement jamais à cause de ces livres).

Cette section se veut être un recueil vivant de l'ensemble des livres recommandés sur le développement PHP en général. Si vous souhaitez ajouter un livre, envoyez une « pull request » (sur github) et votre avis sera relu et rajouté ici si cela est pertinent.

XV-F-1 - Livres gratuits

- PHP The Right Way (en) - Ce site est aussi disponible au format ebook.

XV-F-2 - Livres payants

- Modernizing Legacy Applications In PHP (en) - Gardez le contrôle de votre code PHP ancien via un ensemble d'étapes à appliquer pas à pas

- Building Secure PHP Apps (en) - Pour apprendre les bases en matière de sécurité qu'un développeur expérimenté acquiert au fil des années, le tout condensé dans un livre facile à lire

- The Grumpy Programmer's Guide To Building Testable PHP Applications (en) - Apprendre à écrire du code testable n'est pas forcément ennuyant

- Securing PHP: Core Concepts (en) - Un guide sur les failles de sécurité les plus courantes

- Scaling PHP (en) - Ne jouez plus les sysadmins et retournez à votre code

- Signaling PHP (en) - Les signaux PCNLT sont d'une grande aide lorsqu'il s'agit d'écrire des scripts PHP en ligne de commande.

XVI - Communauté

La communauté PHP est aussi diverse que large et de nombreux membres sont prêts à porter secours aux nouveaux. N'hésitez pas à rejoindre un PHP User Group (PUG) ou à assister à des conférences sur PHP afin d'en apprendre plus sur les meilleures pratiques. Vous pouvez aussi aller sur IRC, canal #phpc du serveur Freenode (irc.freenode.com) et suivre le compte twitter @phpc. Sortez, rencontrez d'autres développeurs PHP, apprenez de nouveaux sujets et par-dessus tout, faites-vous des amis ! Il existe d'autres ressources en ligne comme la page Google+ PHP et StackOverflow.

Voir le calendrier officiel des évènements PHP

XVI-A - PHP User Groups

Si vous vivez dans une grande ville, il y a de fortes chances pour qu'un groupe d'utilisateurs PHP existe. Bien qu'il n'y ait pas de listes officielles, vous pouvez facilement trouver un groupe proche de chez vous en allant sur Google, Meetup.com ou PHP.ug. Si vous vivez dans une ville plus petite, il se peut qu'il n'existe rien encore alors si vous avez suffisamment de motivation, créez-en une !

Lire plus sur les PUG dans le wiki PHP

XVI-B - Conférences PHP

Des conférences PHP ont lieu dans beaucoup de pays de par le monde. Vous y trouverez des membres connus de la communauté PHP, c'est donc une excellente opportunité de rencontrer les leaders de l'industrie.

Trouver des conférences PHP

Note de la rédaction Developpez.com

Developpez.com remercie les initiateurs du projet « PHP, The right way » pour la mise à disposition de ce tutoriel. Les remerciements également à Laethy pour la mise au gabarit et à Claude Leloup pour la relecture orthographique.