Bienvenue

Il existe énormément d’informations obsolètes sur la toile à propos de PHP, ce qui conduit les nouveaux utilisateurs de PHP à prendre de mauvaises habitudes, propageant de mauvaises pratiques et du code peu sûr. PHP: La bonne manière est une référence concise et facile à lire à propos des conventions d’écriture les plus connues sur le PHP, des liens sur les tutoriaux faisant autorité sur le web et des pratiques que les contributeurs de ce document considèrent comme meilleures à l’heure actuelle.

Il n’existe pas une seule et unique façon d’utiliser PHP. Ce site web a pour but d’amener les nouveaux développeurs PHP sur des sujets qu’ils n’auraient pas pu découvrir avant qu’il ne soit trop tard, et vise à donner aux professionnels chevronnés des idées neuves sur ces sujets qu’ils ont pu traiter pendant des années sans s’être penchés dessus. Ce site web ne vous dira pas quels outils utiliser, mais au lieu de cela vous offre des suggestions sur plusieurs options, et quand c’est possible en vous expliquant les différences dans l’approche et les cas d’utilisations.

Ce document n’est pas figé et sera amené à être mis à jour avec des informations utiles et des exemples au fur et à mesure qu’ils seront disponibles.

Traductions

PHP: La bonne manière est (déjà) traduit en plusieurs langues :

Livre

La version la plus récente de PHP: The Right Way (en) est aussi disponible au format PDF, EPUB et MOBI. Voir sur Leanpub

Comment contribuer

Aidez-nous à faire de ce site la meilleure ressource disponible pour les nouveaux programmeurs PHP. Contribuer sur GitHub

Retour en haut

Pour démarrer

Utiliser la dernière version stable (8.0)

Si vous venez juste de commencer à utiliser PHP, prenez soin de débuter avec la dernière version stable de PHP. PHP 8.x a fait de grands progrès en ajoutant de puissantes fonctionnalités au cours des dernières années. Le moteur de PHP 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. Vous devriez migrer vers cette dernière version stable car PHP 5.6 ne reçoit plus de mise à jour de sécurité. La migration reste néanmoins très aisée car il n’existe pas énormement de changements incompatibles.

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.

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

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. Sierra contient la version 5.6.24, High Sierra la version 7.1.6 et Catalina la version 7.3.11.

Installation via un gestionnaire de paquets

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

Installation depuis la source

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.

Installation “Tout-en-un”

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.

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 8.0+, 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 IIS vous donnera le meilleur compromis entre stabilité et performance. Vous pouvez utiliser phpmanager qui est un plugin graphique pour IIS afin d’effectuer les configurations nécessaires pour faire tourner PHP. IIS 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.

Généralement, faire tourner une application sur différents environnement de développement peut conduire à des comportements étranges ce qui peut être hasardeux une fois déployé en production. Si vous développez sous Windows mais que vos machines de production tournent sous Linux, vous feriez mieux de considérer l’utilisation de machines virtuelles.

Il existe toutefois un excellent article en anglais écrit par Chris Tankersley sur les outils à utiliser si vous souhaitez travailler sous Windows.

Retour en haut

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, le PSR-1, le PSR-2 et le PSR-4. Ces recommandations sont un ensemble de règles que certains projets ont adoptées comme Drupal, Zend, Symfony, Laravel, 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.

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.

Utiliser le PHP Coding Standards Fixer de Fabien Potencier afin de formatter 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 les comprendre.

Retour en haut

Les points importants du langage

Les paradigmes de programmation

Le PHP est un langage flexible et dynamique, supportant une variété de techniques 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).

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.

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).

Méta-programmation

Le PHP supporte différentes formes de méta-programmation à 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() et __callStatic().

PHP 8.0 (2020) apporte maintenant le principe d’annotations avec PHP 8.0 (2020) permettant de rajouter des métadonnées sur les classes et les méthodes.

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 nom, il peut y avoir des collisions de noms, ce qui pose problème.

Les espaces de nom résolvent ce problème. Comme décrit dans le manuel de référence PHP, les espaces de nom 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 nom distincts.

Il est important pour vous que vous utilisiez les espaces de nom 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 nom se trouve dans le PSR-0 qui vise à fournir un fichier standard, une convention pour les classes et les espaces de nom 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 2 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 pensez utiliser un standard d’autochargement pour une nouvelle application ou un paquetage alors vous devriez certainement voir du côté de PSR-4.

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), les tas (heap) et des itérateurs qui peuvent parcourir ces structures ou vos propres classes implémentant les interfaces SPL.

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 ces essais, créez un fichier nommé hello.php et écrivez le code ci-dessous.

<?php
if ($argc != 2) {
    echo "Usage: php hello.php [nom].\n";
    exit(1);
}
$nom = $argv[1];
echo "Hello, $nom\n";

Le PHP crée 2 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:

> php hello.php
Usage: php hello.php [nom]
> php hello.php world
Hello, world

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 debogueur de PHP, peut être utilisé par de nombreux EDIs pour fournir des fonctionnalités telles que les point d’arrêts 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 “deboguage à distance” - Si vous développez du code localement et que vous testez ensuite sur une machine virtuelle voir un autre serveur alors le déboguage à distance vous permettra de le faire sans problème.

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

php_value xdebug.remote_host=192.168.?.?
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:

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êts 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éboguage avec xdebug. MacGDBp est un xdebug gratuit, open-source pour Mac.

Retour en haut

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 sûrement 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.

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.

Composer et Packagist

Composer est 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ées par votre projet. Ces “paquets” sont listés sur Packagist, le répertoire officiel pour les bibliothèques compatibles avec Composer.

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 :

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

Cela va télécharger composer.phar qui est une archive PHP binaire. Vous pouvez la 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.

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.

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:

É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 :

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

Le chemin $HOME/local/bin (ou le répertoire de votre choix) doit être dans la variable d’environement $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 part du principe que vous avez installé Composer “globlalement”.

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:

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:

composer install

Ensuite, ajoutez cette ligne dans le fichier PHP principal de votre application; cela va dire à PHP d’utiliser l’auto-chargeur de Composer pour les dépendances de votre projet:

<?php
require 'vendor/autoload.php';

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

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 toutes les dépendances, exécuter 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 * comme 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.

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.

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.

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 2 projets ayant besoin de versions différentes.

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.

Comment installer un paquet

Si le paquet est listé 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 une autre canal, vous aurez alors besoin de découvrir ce canal et aussi de le spécifier lors de l’installation. Voir les docs sur l’utilisation des canaux pour plus d’informations sur ce sujet.

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, vous pouvez utiliser Composer pour gérer les dépendances à PEAR. L’exemple suivant va installer du code de pear2.php.net:

{
    "repositories": [
        {
            "type": "pear",
            "url": "http://pear2.php.net"
        }
    ],
    "require": {
        "pear-pear2/PEAR2_Text_Markdown": "*",
        "pear-pear2/PEAR2_HTTP_Request": "*"
    }
}

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:

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’auto-chargeur de Composer:

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:

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

Retour en haut

Pratiques de programmation

Les bases

PHP est un language 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 programmation de base de PHP.

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 cette dernière fournit une interface orientée objet à la plupart des usages courants. Elle 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 méthode 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.

<?php
$raw = '22. 11. 1968';
$start = \DateTime::createFromFormat('d. m. Y', $raw);

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 très facile à afficher.

<?php
// créer une copie de $start et ajouter un mois et six jours
$end = clone $start;
$end->add(new \DateInterval('P1M6D'));

$diff = $end->diff($start);
echo 'Différence: ' . $diff->format('%m mois, %d jours (total: %a jours)') . "\n";
// Différence: 1 mois, 6 jours (total: 37 jours)

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

<?php
if ($start < $end) {
    echo "$start est avant $end!\n";
}

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 2 objets DateTime, start et end, et l’intervalle pour lequel tous les évènements seront retournés.

<?php
// affiche tous les jeudis entre $start et $end
$periodInterval = \DateInterval::createFromDateString('first thursday');
$periodIterator = new \DatePeriod($start, $periodInterval, $end, \DatePeriod::EXCLUDE_START_DATE);
foreach ($periodIterator as $date) {
    // affiche chaque date pour la période
    echo $date->format('m/d/Y') . ' ';
}

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 plupart 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.

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.

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.

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 contre-partie mb_* comme mb_strpos() et mb_strlen(). Ces fonctions mb_* proviennent de l’extension pour les chaînes de caractères multi-octets et ont été conçus spécialement pour les chaînes Unicode.

Vous devez utiliser les fonctions mb_* à chaque fois que vous manipulez une chaîne de caractère Unicode. Par exemple, si vous utilisez substr() sur une chaîne UTF-8, il y a de forte chance 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 grande chance 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 tout 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ère de vos chaînes vous simplifiera énormement 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ère. 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().

Au final, 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.

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 soit 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.

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.

<?php
// Indique à PHP que nous allons effectivement manipuler du texte UTF-8
mb_internal_encoding('UTF-8');

// indique à PHP que nous allons afficher du texte UTF-8 dans le navigateur web
mb_http_output('UTF-8');

// Notre chaîne UTF-8 de test
$string = 'Êl síla erin lû e-govaned vîn.';

// Découpe une sous partie de la chaîne à l'aide d'une fonction multi-octet
// Notez que la découpe se fait au niveau d'un caractère non-ascii pour la démonstration
$string = mb_substr($string, 0, 15);

// Connexion à une base de données pour stocker la chaîne transformée
// Voir les exemples d'utilisation de PDO dans ce document
// Notez la commande `set names utf8mb4`
$link = new \PDO(
                    'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
                    'your-username',
                    'your-password',
                    array(
                        \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
                        \PDO::ATTR_PERSISTENT => false
                    )
                );

// Stocke notre chaîne en tant que chaîne UTF-8 dans la base de données
// Votre base ainsi que ses tables doivent être encodées avec utf8mb4 (character set et collation).
$handle = $link->prepare('insert into ElvishSentences (Id, Body) values (?, ?)');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->bindValue(2, $string);
$handle->execute();

// Récupère la chaîne que l'on vient juste de stocker pour prouver qu'elle a été correctement stockée
$handle = $link->prepare('select * from ElvishSentences where Id = ?');
$handle->bindValue(1, 1, PDO::PARAM_INT);
$handle->execute();

// stocke le résultat dans un objet que l'on affichera dans notre HTML
$result = $handle->fetchAll(\PDO::FETCH_OBJ);

header('Content-Type: text/html; charset=utf-8');
?><!doctype html>
<html>
    <head>
        <title>page de test UTF-8</title>
    </head>
    <body>
        <?php
        foreach($result as $row){
            print($row->Body);  // Cela devrait correctement afficher notre contenu en UTF-8
        }
        ?>
    </body>
</html>

Pour aller plus loin

Retour en haut

Injection de dépendance

De Wikipedia:

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.

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 instantions 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.

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct()
    {
        $this->adapter = new MySqlAdapter;
    }
}

class MysqlAdapter {}

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

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct(MySqlAdapter $adapter)
    {
        $this->adapter = $adapter;
    }
}

class MysqlAdapter {}

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

Problèmes complexes

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.

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 terme 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 avons besoin et ce sans avoir à écrire en dur quelque dépendance que ce soit.

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 abstactions 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.

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct(AdapterInterface $adapter)
    {
        $this->adapter = $adapter;
    }
}

interface AdapterInterface {}

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 constuira 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.

Conteneurs

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 anti-pattern. 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.

Lecture approfondie

Attention, les liens qui suivent sont tous en anglais :

Retour en haut

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 base 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 pas utiliser les mêmes pilotes. Vous aurez besoin d’apprendre une nouvelle API pour chaque type de BDD — ce qui peut devenir lourd.

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 quelle fonction 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

Extension PDO

PDO est une couche d’abstraction pour se connecter à une base de données — intégrée à PHP depuis la version 5.1.0 — qui fournit une interface commune pour communiquer avec différentes bases de données. 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, 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çoit 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 :

<?php
$pdo = new PDO('sqlite:users.db');
$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.

<?php
$pdo = new PDO('sqlite:users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$stmt->bindParam(':id', $_GET['id'], PDO::PARAM_INT); // <-- Nettoyé automatiquement par PDO
$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 dans la base de données, ce qui empêche les attaques potentielles par injection SQL.

Vous devriez savoir que les connexions à la base de données utilisent pas mal de ressources et il arrivait souvent que les ressources finissaient 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 s’assurant que toutes les références à cet objet ont été supprimées, c’est-à-dire, mises à 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.

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; elles peuvent donc être installées dans n’importe quelle application qui vous plaira :

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 :

<ul>
<?php
foreach ($db->query('SELECT * FROM table') as $row) {
    echo "<li>".$row['field1']." - ".$row['field1']."</li>";
}
</ul>

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

Bien qu’il existe un certain nombre de solutions pour parer à 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 :

<?php
function getAllFoos($db) {
    return $db->query('SELECT * FROM table');
}

foreach (getAllFoos() as $row) {
    echo "<li>".$row['field1']." - ".$row['field1']."</li>"; // MAUVAIS!!
}

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

<?php

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

// Rendre votre modèle accessible
include 'models/FooModel.php';

// Création d'une instance
$fooList = new FooModel($db);

// Affichage du résultat
include 'views/foo-list.php';

models/FooModel.php

<?php
class Foo()
{
    protected $db;

    public function __construct(PDO $db)
    {
        $this->db = $db;
    }

    public function getAllFoos() {
        return $this->db->query('SELECT * FROM table');
    }
}

views/foo-list.php

<? foreach ($fooList as $row): ?>
    <?= $row['field1'] ?> - <?= $row['field1'] ?>
<? 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.

PHPBridge contient un excellent tutoriel appellé Creating a Data Class qui couvre un sujet similaire à celui-ci et permet de bien s’imprégner du concept d’interaction avec les bases de données.

Couches d’abstraction

Pratiquement tous les frameworks contiennent leurs propres couches d’abstraction qui peut ou non se baser sur PDO. Il simule la plupart du temps les caractéristiques manquantes d’un système à l’autre en englobant vos requêtes dans des méthodes PHP vous donnant une réelle abstraction des données contrairement à PDO qui ne vous fournit que la partie connexion. Cela rajoute évidemment une surcouche mais si vous devez construire une application portable qui nécessite de travailler à la fois avec MySQL, PostgreSQL et/ou SQLite alors ce petit surplus ne sera pas de trop afin d’avoir un code plus maintenable.

Certains couches d’abstraction ont été construites en utilisant la norme PSR-0 ou PSR-4 afin d’être utilisable par n’importe quelle application:

Retour en haut

Templating

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

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 (responsables 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éfinis 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 sandboxing) définis dans une liste blanche de façon, par exemple, à limiter les dégats collatéraux provoqués par une mauvaise utilisation faites par les designers.

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 language de templating. Ce terme signifie tout simplement que vous pouvez combiner du code PHP avec un autre langage comme l’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):

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

<h1>Profil utilisateur</h1>
<p>Bonjour, <?=$this->escape($name)?></p>

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

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):

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

<h1>Profil utilisateur</h1>
<p>Bonjour, {{ name }}</p>

{% include 'footer.html' %}

Aller plus loin

Articles & Tutoriels

Bibliothèques

Retour en haut

Les erreurs et exceptions

Erreurs

Le PHP a plusieurs niveaux de gravité pour les erreurs. Les 3 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.

Exceptions

Les exceptions sont une partie standardisée dans la plupart des langages de programmation populaire 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ées) 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 rendu évidente à comprendre.

L’autre problème arrive lorsque les classes lancent automatiquement une erreur à l’écran et terminent 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:

<?php
$email = new Fuel\Email;
$email->subject('Mon sujet');
$email->body('Comment allez-vous ?');
$email->to('guy@exemple.com', 'Un gars');

try
{
    $email->send();
}
catch(Fuel\Email\ValidationFailedException $e)
{
    // La validation a échoué
}
catch(Fuel\Email\SendingFailedException $e)
{
    // Le pilote ne peut pas envoyé l'email
}
finally
{
    // ce bloc est exécuté même si une exception a été levée et avant que l'exécution normale reprenne
}

Les exceptions SPL

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

<?php
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 aurait 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 lever une exception standard vague ou d’utiliser une sous-classe personnalisée, vous pourriez tout simplement faire throw new BadFunctionCallException;.

Retour en haut

Sécurité

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é.

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 mot 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 2 chaînes sont différentes (‘secret-password’ vs. ‘bad-password’), l’authentification va échouer.

<?php

require 'password.php';

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

if (password_verify('bad-password', $passwordHash)) {
    // Mot de passe correct
} else {
    // Mauvais mot de passe
}

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 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 superglobale $_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 sûres.

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 de l’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.

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 nettoyera les entrées pour vous.

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

Voir les filtres de nettoyage

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

Fichiers de configuration

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

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 inclus 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.

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.

Développement

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

display_errors = On
display_startup_errors = On
error_reporting = -1
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 parti de E_ALL, cependant il est dorénavant inclu 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

Production

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

display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
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:

Retour en haut

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érentes 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.

Développement dirigé par les tests (TDD)

Citation tirée de Wikipedia:

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

Il existe différents types de test que vous pouvez faire sur votre application.

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 alternative 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(s) 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 alternatives :

Test d’intégration

Citation tirée de Wikipedia:

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.

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 terme 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 scenarii réalistes d’utilisation.

Outils pour les tests fonctionnels

Behavior Driven Development

Il existe 2 types de développement orientés comportement (BDD en anglais) : SpecBDD et StoryBDD. SpecBDD se concentre sur 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 language 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.

Liens sur le BDD

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.

Liens vers les outils

Retour en haut

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.

Platform as a Service (PaaS)

Les PaaS fournissent l’architecture système et réseaux nécessaires 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.

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 donne un contrôle absolu sur l’environement de production de votre application.

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.

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 terme 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 terme d’utilisation mémoire et plus rapide mais cela demandera plus de travail pour la mettre en place.

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 soit 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.

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 voir même 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:

Outil de construction automatique

Les outils de contruction 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. Ils ne font généralement pas parti 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écessaires 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 à avancé pour exécuter des commandes de façon structuré 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.

Les ressources sur Chef pour les développeurs PHP:

Allez plus loin:

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égrations 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).

Allez plus loin:

Retour en haut

Virtualisation

Faire tourner vos applications sur différents environnements en développement et en production peut vous amener à rencontrer d’étranges bugs 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 (Virtual Machine, abrégé en VM en anglais).

Vagrant

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.

Un coup de pouce

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

Docker

Docker est une alternative légère par rapport à une machine virtuelle. Son nom provient du fait qu’il manipule des “conteneurs”. Un conteneur est le bloc de base qui dans un cas simple n’accomplit qu’une tâche spécifique, par exemple faire tourner un serveur web. Une “image” est l’instantané que vous utilisez pour construire un conteneur - Docker en répertorie un grand nombre.

Une application LAMP peut typiquement avoir 3 conteneurs: un pour le serveur web, un pour le processus PHP-FPM et le dernier pour MySQL. Tout comme les dossiers partagés avec Vagrant, vous pouvez laisser vos fichiers où ils se trouvent et indiquer leurs emplacements à Docker.

Vous pouvez générer des conteneurs depuis la ligne de commande (voir l’exemple ci-dessous) ou, pour des questions de maintenance, créer un fichier docker-compose.yml qui contiendra l’ensemble des éléments et la façon dont ils communiquent entre eux.

Docker peut vous aider si vous développez plusieurs sites et que vous souhaitez avoir la séparation d’environnement que vous pourriez l’avoir avec une machine virtuelle sans la lourdeur de devoir installer un système d’exploitation complet. Non seulement le téléchargement et l’installation d’un conteneur se fait très rapidement mais en plus vous bénéficiez aussi d’un stockage réduit car vous pourrez réutiliser les images communes entre vos différents sites.

Exemple: Faire tourner PHP sous Docker

Après avoir installer docker sur votre machine vous pouvez démarrer le serveur web en une commande. La commande suivante vous permettra de disposer d’une installation Apache complète avec la dernière version de PHP visible sur http://localhost:8080 où la racine du projet pointe vers /mon/chemin/vers/fichiers_php :

docker run -d --name my-php-webserver -p 8080:80 -v /mon/chemin/vers/fichiers_php:/var/www/html/ php:apache

Cela va initialiser puis installer votre conteneur. l’option -d le fait tourner en arrière plan. Pour l’arrêter ou le démarrer, lancer tout simplement docker stop my-php-webserver ou docker start my-php-webserver (pas besoin de renseigner les autres paramètres).

En savoir plus sur Docker

La commande ci-dessus vous montre une façon rapide de mettre en place un serveur web. Il y a encore pleins de choses possibles à faire (et des milliers d’images disponibles sur Docker Hub). Prenez le temps de vous familiariser avec la terminologie et lisez le manuel utilisateur pour en savoir plus. Gardez cependant à l’esprit de ne jamais faire tourner d’images inconnues et en cas de doute, n’utilisez que les dépôts officiels.

Le site PHPDocker.io vous permet d’auto-générer les fichiers nécessaires pour créer une pile LAMP/LEMP en y incluant la version PHP de votre choix ainsi que ses extensions.

Retour en haut

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 appplications ou pour réduire le nombre de fois où ces actions consommatrices de temps ont besoin de se lancer.

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:

Cache des objets

Il arrive parfois qu’il soit plus avantageux de mettre en cache des objets individuels dans votre code comme 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 de 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 APIs 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é 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 terme 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:

<?php
// vérifie si la variable 'expensive_data' existe dans le cache
$data = apc_fetch('expensive_data');
if ($data === false) {
    // la donnée n'est pas en cache; enregistrer le résultat de l'appel d'une fonction longue pour plus tard
    apc_add('expensive_data', $data = get_expensive_data());
}

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:

Retour en haut

Documentation du code

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 pour être trouvé sur le manuel PHPDoc.

Vous trouverez ci-dessous un exemple d’utilisation des principaux tags;

<?php
/**
 * @author Votre nom <nom@exemple.com>
 * @link http://www.phpdoc.org/docs/latest/index.html
 * @package helper
 */
class DateTimeHelper
{
    /**
     * @param mixed $anything Tout ce qui peut être traduit en un objet \DateTime
     *
     * @return \DateTime
     * @throws \InvalidArgumentException
     */
    public function dateTimeFromAnything($anything)
    {
        $type = gettype($anything);

        switch ($type) {
            // Ce bloc doit retourner un objet \DateTime
        }

        throw new \InvalidArgumentException(
            "Impossible de convertir '{$type}' en un objet DateTime"
        );
    }

    /**
     * @param mixed $date Tout ce qui peut être traduit en un objet \DateTime
     *
     * @return void
     */
    public function printISO8601Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('c');
    }

    /**
     * @param mixed $date Tout ce qui peut être traduit en un objet \DateTime
     */
    public function printRFC2822Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('r');
    }
}

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 parti 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 renvoit un résultat, il faut l’indiquer avec le tag @return et utilisez @throws autant de fois qu’il y a d’exceptions levées.

La seconde et la troisième méthodes sont très similaires et on 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 renvoit rien (si vous omettez ce tag, c’est cette valeur qui sera indiqué 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.

Retour en haut

Ressources

Officielles

Personnes à suivre

Mentorat

Fournisseurs PaaS pour PHP

Pour savoir quelles versions tournent sur ces hébergeurs, dirigez-vous vers PHP Versions.

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 3 sortes :

Les micro-frameworks 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éveloppmeent tel 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 micro-framework et ceci sont appelés “framework full-stack”. Ils sont souvent fourni avec des ORMs, des packages d’authentification, etc.

Les frameworks orienté 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.

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 2 plus connus sont :

Chacun de ces 2 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 :

Les composants Illuminate de Laravel listés ci-dessus sont découplés du framework.

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 verra 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 ajouté ici si cela est pertinent.

Livres gratuits

Livres payants

Retour en haut

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 ! Ils existent d’autres ressources en ligne comme la page StackOverflow.

Voir le calendrier officiel des évènements PHP

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 PUGs dans le wiki PHP

Conférences PHP

Des conférences PHP ont lieu dans beaucoup de pays de part 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