IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

PHP : La bonne manière

Sous-titre

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 focntionnalité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é car il n'existe pas énormement de changements incompatibles.

Ne vous laissez pas avoir par le numéro de version mineur 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écuter la ligne de commande suivante dans un terminal à la racine de votre projet : > php -S localhost:8000

Apprenez en plus sur l'outil en ligne de commandes

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 gestionnaire 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échargez 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, visiter 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 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. 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é manuellement ou via des outils comme Puppet ou Chef. Configurer ces systèmes de façon automatisé 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éez un nouveau de façon entièrement automatisé ce qui facilite les nouvelles installations.

Vagrant crée des dossiers partagés utilisé 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 3 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 énormement sur PHP. Par ailleurs, des VMs locales peuvent être utilisées pour déployer des services clouds. 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é 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 convention de codage. Celles qui sont liées au convention 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é comme Drupal, Zend, Symfony, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium, etc. Vous pouvez les utiliser dans vos projets ou bien la votre 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éé 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 quel langue du moment que l'ensemble des personnes ayant à travailler dessus puissent le comprendre.

III. Les points importants du language

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 principe de programmation orienté 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.

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érençées par une variable et invoquées dynamiquement. Les fonctions peuvent être passés en tant qu'argument à d'autres fonctions (on parle alors de fonctions d'ordre supérieure) 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 concentre 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és aussi bien avec les fonctions anonymes (dans la plupart des cas).

III-A-3. Méta-programmation

Le PHP supporte différentes formes de méta-programmation à travers des mécanismes tel 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().

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és 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, 2 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 une 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ée 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émente 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.

III-C. La bibliothèque PHP standard

La bibliothèque standard PHP (SPL en anglais) est fourni avec PHP et donne accès à une collection de classes et d'interfaces. Elle est composé de classes permettant de manipuler les structure 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é”. 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 ses essais, créez un fichier nommé hello.php et écrivez le code ci-dessous.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
<?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és 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é 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 trouve ici.

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

 
Sélectionnez
1.
2.
3.
4.
> php hello.php
Usage: php hello.php [nom]
> php hello.php world
Hello, world

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 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 la faire sans problème.

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

 
Sélectionnez
1.
2.
php_value xdebug.remote_host=192.168.?.?
php_value xdebug.remote_port=9000

Le “remote host” et “remote port” conrespondent à 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:

 
Sélectionnez
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ê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.

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étez des autoloaders. Mais plus maintenant.

À l'heure actuelle, ils existent 2 gestionnaire de packaging pour PHP - Composer et PEAR. Lequel correspond le mieux à vos attentes ? Cela dépend de la taille de votre projet.

  • Utiliser Composer pour la gestion des dépendances d'un seul projet.
  • Utiliser 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, ils existent 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 utiliser 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 :

 
Sélectionnez
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, ils existent 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 certaines répertoires
  • possède des extensions problématiques qui ne seront alors pas chargées
  • a les bonnes configurations au niveau du fichierphp.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 :

 
Sélectionnez
1.
2.
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 assume 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:

 
Sélectionnez
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é et qui possèdent déjà un fichier composer.json:

 
Sélectionnez
1.
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:

 
Sélectionnez
1.
2.
<?php
require 'vendor/autoload.php';

Maintenant si vous utiliser 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 paquets 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.locky est inclu alors ils auront les mêmes versions que vous. Pour mettre à jour ces 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.

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 Composermais 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é pour PEAR ne marchera pas.

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

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

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

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
{
    "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é 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:

 
Sélectionnez
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'auto-chargeur de Composer:

 
Sélectionnez
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:

 
Sélectionnez
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 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 programmations de bases de PHP.

V-B. La date et le temps

Le PHP a une classe nommé 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é 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.

 
Sélectionnez
1.
2.
3.
4.
5.
<?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 super facile à afficher.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<?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:

 
Sélectionnez
1.
2.
3.
4.
<?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 laquelle tous les évènements seront retournés.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<?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') . ' ';
}

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

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

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ée et les tables qu'elle contient sont toutes enregistrées avec l'encodage de caractères et la collation utf8mb4et que votre connexion PDO soit aussi mis 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.

La 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 HTTPContent-Typeest en fait plus rapide.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
<?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  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é
$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>

V-D-5. Pour aller plus loin

VI. Injection de dépendance

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 instantions l'adaptateur à l'intérieur du constructeur et créeons une dépendance forte. Cela rend les tests compliqués étant donné que la classe Database est fortement couplée à l'adaptateur.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<?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épendance et ainsi délier l'adaptateur de la classe.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<?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ê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 terme d'injection de dépendance, 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érités 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épendance 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 ceux sans avoir à écrire en dur quelques dépendances 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é 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 “concretes”. Nous pouvons facilement refactoriser l'exemple ci-dessus en suivant ce principe.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
<?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 factif implémentant cette interface en sachant que notre collègue constuira l'adaptateur en respectant le contrat de base.

Un bénéfice entre 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 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.

VII. Bases de données

Votre code PHP va souvent faire appel aux base 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 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é depuis PHP 5.5.0 ce qui signifie qu'il sera retiré 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

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 base 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 base 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çoit un identifiant numérique en tant que paramètre d'entrée. Cet ID devrait être utiliser pour récupérer les enregistrements d'un utilisateur dans la base de données. Voici la mauvaise façon de s'y prendre:

 
Sélectionnez
1.
2.
3.
<?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.

 
Sélectionnez
1.
2.
3.
4.
5.
<?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 à 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 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és, 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é 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égèr surplus mais si vous voulez développez 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é dans n'importe quelle application qui vous plaira:

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

 
Sélectionnez
1.
2.
3.
4.
5.
6.
<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 du 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 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és.

Considérez l'exemple suivant :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
<?php
function getAllSomethings($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 distincts.

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

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
<?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

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
<?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

 
Sélectionnez
1.
2.
3.
<? 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.

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

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 formatté. 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éfini 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 offre même la possibilité d'isoler les variables et les fonctions (on parlera de “sand-boxing”) définis dans une liste blanche de façon, par ex., à limiter les dégats collatéraux provoqués par une mauvaise utilisation faites 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 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 rapide é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.Viewrendent 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):

 
Sélectionnez
1.
2.
3.
4.
5.
6.
<?php $this->insert('header', ['title' => 'Profil utilisateur']) ?>

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

<?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és. 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. Etant 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):

 
Sélectionnez
1.
2.
3.
4.
5.
6.
{% include 'header.html' with {'title': 'Profil utilisateur'} %}

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

{% include 'footer.html' %}

IX. Les erreurs et exceptions

IX-A. Erreurs

Le PHP a plusieurs niveau de gravité pour les erreurs. Les 3 types de messages d'erreurs les plus communs sont les erreurs, les avertissements et les remarques. Ils existent 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é.

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 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é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 rendu é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 pourra plus capable de gérer cette erreur à l'exécution. Les exceptions devraient être lançées afin d'avertir le développeur qu'une chose ne s'est pas passé comme prévu; ça devrait être à eux de décider comment ils veulent gérer cela, par exemple:

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
<?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ée
}
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é et avant que l'exécution normale reprenne
}

IX-B-1. 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 :

 
Sélectionnez
1.
2.
<?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 éviter si les exceptions de la SPL avaient été utilisés avec l'extension SPL.

Si par exemple vous utilisez la méthode magique __call() et qu'une méthode invalide est demandé 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;.

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 utiliser plus tard pour authentifier les utilisateurs.

Il est important que vous utilisiez correctement les fonctions de hachage avant de les stocker. Le hachage de mot 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é introduise avec la version 5.5 de PHP. À l'heure actuelle, elle utilise BCrypt qui est l'algorithme le plus robuste. Cela va être mise à 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 échoué.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
<?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
}

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 à “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és 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és et qu'elles peuvent être considérées comme sûr.

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 dangereux. 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 exploiter en changeant le chemin vers le fichier. Vous devez supprimez “/”, “../”, 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.

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

Parfois il est nécessaire d'autoriser certains tags HTML dans les entrées quand on les incluent 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

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 meilleurs 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 inclue 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 possible durant le dévelopement, configurer les paramètres suivants dans votre fichier php.ini:

 
Sélectionnez
1.
2.
3.
4.
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

  • < 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, configurer votre fichier php.ini de cette façon:

 
Sélectionnez
1.
2.
3.
4.
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 afficher à l'utilisateur. Pour plus d'informations sur ces paramètres, voir le manuel PHP:

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 devrait pas être ignoré.

Il existe différentes types d'outils de test (ou framework) disponible 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 logiciel 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évues 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 meilleur 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 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 :

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 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 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'acceptance
  • Storyplayer est un framework de test complet qui inclue un support pour créer et détruire des environnements de test à la demande

XI-B. Behavior Driven Development

Il existe 2 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 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.

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

XII. Les serveurs et le déploiement

Les applications PHP peuvent être déployés et exécutés 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éseaux 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 donne un contrôle absolu sur l'environement 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.

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

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érifier tout de même que ce soit la dernière version qui soit installé. Les hébergements mutualisés vous permette à 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 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:

  • 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 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. Il ne fait généralement pas parti du logiciel en lui-même, agissant ainsi depuis l'extérieur.

Il existe beaucoup d'outils open-source disponible pour vous aider à automatiser la construction de votre application, certains étant même écrit 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 à 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.

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é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 ceux 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, ils 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.

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 significatif la réactivité de votre applicaiton. 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:

XIII-B. 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érer 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 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:

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
<?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:

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

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

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
<?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.

XV. Ressources

XV-A. Officielles

XV-B. Mentorat

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

XV-C. Fournisseurs PaaS pour PHP

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 fournit 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
  • Les frameworks complets (“full-stack” en anglais)
  • Les frameworks orienté composant

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.

Frameworks PHP populaires

XV-E. Mentorat

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

XV-F. Fournisseurs PaaS pour PHP

XV-G. 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 fournit 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
  • Les frameworks complets (“full-stack” en anglais)
  • Les frameworks orienté composant

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.

XV-H. 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 leur sont associé afin d'installer et de mettre à jour les processus, ce qui est expliqué plus en détail dans la section gestion des dépéndances

Il existe aussi des frameworks basé sur les composants qui vous permette 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 :

XV-I. Livres

Il existe un grand nombre de livres autour du PHP mais un certain nombre sont malheureusement obsolète 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-I-1. Livres gratuits

XV-I-2. Livres payants

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

XVI-B. 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

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2016 Josh Lockhart. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.