Bien débuter sa lib PHP: Part I – Les outils

GitHub, IDE, Travis, Scrutinizer, Insight, Composer, Packagist, …

Ce premier article sur les bonnes pratiques de développement d’une librairie PHP propose de passer en revue les principaux outils à mettre en place en débutant son projet. Ces outils touchent au versionning, au formatage du code et à la gestion des dépendances. Nous verrons qu’ils permettent la mise en place d’un processus d’intégration continue d’un projet.

Cet article n’est assurément pas exhaustif. Il n’en a d’ailleurs pas la vocation. Il s’agit avant tout d’un aperçu des solutions les plus en vogue, et de dégager de facto les principaux standards actuels. Par exemple, en matière de versionning, je ne parle que de Git, alors qu’il existe bien sûr d’autres solutions du même type (dont certaines que vous, personnellement, préférerez).

Ce choix est arrêté arbitrairement, de par la popularité de l’outil, sa facilité ou sa puissance d’utilisation. Pour revenir à notre exemple, Git est extrêmement polyvalent en lui-même, il s’est imposé auprès d’une large partie de la communauté, et il permet de s’interfacer facilement avec GitHub, qui lui-même s’interface facilement avec les serveurs d’intégration en ligne ainsi qu’avec les gestionnaires de dépendance, etc. Cela ne veut pour autant pas dire que d’autres solutions ne sont pas envisageables.

Enfin, il ne s’agit pas non plus d’expliquer en profondeur ces outils. Chaque outil fera l’objet d’une présentation globale résumant ses principales fonctionnalités. Nous essaierons de dégager les impacts directs touchant le projet et de lister un maximum de ressources intéressantes pour approfondir le sujet.

Par contre, peut-être ai-je oublié certains points, certaines bonnes pratiques essentielles. Si vous en connaissez ou si vous pensez à certaines ressources intéressantes, n’hésitez pas à les partager dans les commentaires!

Pour finir, sachez que l’ensemble des bonnes pratiques dégagées dans cette série d’articles seront consignées dans un projet GitHub représentant une sorte de bootstrap plus ou moins idéal d’un projet PHP. Deplus, une check-list résumant les principaux points est sur Gist.

Le versionning

Le versonning c’est quoi? Si jamais vous ne connaissez pas, retenez que, en gros, cela permet de partager ses développements (et dès lors de déployer une application) et de garder un historique des modifications (et dès lors de gérer les versions d’une application). S’il n’y a qu’une seule bonne pratique que vous deviez mettre en place, et ce dans tous les cas, c’est bien de versionner votre projet.

Git

Git est le logiciel de versionning qui s’est imposé ces dernières années. Puissant, léger, pratique: Git, c’est génial. :) Parmi ses atouts, on comptera entre autres la possibilité de gérer plusieurs branches très facilement ainsi que de nettoyer son historique avant de partager ses commit.

Config

Une bonne utilisation de Git nécessite que l’on ajoute .gitignore, un fichier de configuration situé à la racine du projet. Il permet de spécifier les path qui ne doivent pas être versionnés. Le projet gitignore.io vous propose de générer vos fichiers sur base des exemples proposés par GitHub.

Fichiers versionnés

.gitignore
.gitattributes (en cas de besoin)

Doc et tutos

Se lancer dans Git avec la doc officielle ou avec un tuto vidéo.

GitHub

Fonctionnalités

GitHub, quant à lui, s’est imposé comme l’un des principaux dépôts distants pour Git. Sa grande force: il est gratuit pour l’open-source, facile d’utilisation et fort complet. Parmi ses principales fonctionnalités:

  • Partage du code: visualiser le code, l’historique, les contributions, les release…
  • Gestion des métadonnées: gérer les issues, la documentation, les discussions, …

Doc et tutos

Se lancer dans GitHub avec la doc officielle ou avec un tuto en vidéo. Un tuto sur la gestion des pull request.

Les éditeurs de code

Pour ma part, j’utilise PHPStorm et j’en suis extrêmement satisfait. Mais peu importe votre éditeur de code, pourvu que vous respectiez les formatages suivants:

File encoding

Le standard actuel d’encodage des fichiers, tel que défini par la PSR-1, est l’UTF-8 sans BOM. (Attention que ni PHP ni même le HTML ne gèrent le BOM.)

PHP supporte initialement l’ISO 8859-1. Aussi certaines fonctions de manipulation des string pourraient avoir un comportement inattendu sur les caractères non compatibles avec l’ASCII. C’est pourquoi il est recommandé de travailler avec l’extension mbstring.

D’autre part, le comportement de certaines fonctions peut également changer selon les versions de PHP, comme par exemple htmlentities qui supporte par défaut l’UTF-8, mais seulement depuis 5.4.0.

Si vous travaillez sur un projet web, le header HTTP doit également être adapté via la fonction header ou de la directive default_charset. Egalement en matière d’interfaçage, il sera important de vous soucier de votre base de données (connexion et format des données). (Attention que pour Mysql, le charset utf8 est codé sur 3 bytes (utf8mb3) au lieu de 4 (utf8mb4). Mysql parle de ce problème dans sa doc.)

Je vous recommande le résumé de PHP Best Practices ainsi que ce post stackoverflow sur la migration d’un projet PHP en UTF-8.

Réglage dans PHPStorm: Project Settings > File Encodings

Line separator

PHP tournant sur Linux, on utilisera le saut de ligne (LF, line feed, \n) comme séparateur de ligne, tel que défini par la PSR-2. A priori, si votre éditeur de code est un minimum intelligent, cela ne posera aucun problème, même si, en local, vous ne travaillez pas sous Linux.

Attention également à la gestion de ce caractère avec Git: le paramètre core.autocrlf peut convertir les fins de ligne. Si votre IDE est bien configuré et gère vos fins de ligne, ce paramètre de Git peut être modifié pour « input » (`git config –global core.autocrlf input`).

Une autre façon de gérer ce problème est de forcer les fins de ligne grâce à une commande passée dans le fichier .gitattributes de Git. Il est en effet possible de demander à Git de convertir les fins de ligne de tous les fichiers texte:

//.gitattributes
* text eol=lf

Réglage dans PHPStorm: Project Settings > Code Style > General

Coding style

Et bien sûr, il faut formater le code lui-même selon le style de codage que vous aurez choisi. La norme actuelle pour PHP est résumée dans les PSR 1 et 2.

Réglage dans PHPStorm: Project Settings > Code Style

Fichiers versionnés

Le projet EditorConfig permet, grâce à des plugin, de bénéficier d’un fichier de config cross-IDE gérant quelques-uns de leurs paramétrages: .editorconfig

Par ailleurs, faites attention de ne pas versionner les dossiers ou fichiers propres aux IDE (Pour PHPStorm: /.idea). Cela pourrait, par exemple, être fait à l’aide du fichier .gitignore. Il existe des exemples de config dédiés à cette problématique.

Toutefois, dès lors que votre .gitignore est versionné et donc partagé avec tous, cela risque d’être fort lourd: si vous le faites pour un IDE, vous devrez le faire pour tous les IDE, sans compter les fichiers spécifiques aux OS.

Une meilleure pratique consiste donc à exclure les particularités de votre environnement de travail dans le fichier .git/info/exclude, spécialement dédié à cet effet et qui, lui, n’est pas versionné.

Une autre possibilité est de configurer un .gitignore global qui sera commun à tous vos repository. Cela aura pour avantage de ne devoir être configuré qu’une seule et unique fois pour tous vos projets.

Les serveurs d’intégration continue

Quelques outils deviennent incontournables, car ils vous permettent de publier un code stable et de qualité. Dans cette partie, on parlera de build et de qualité de code. Par « build », on entend le déploiement automatisé d’un projet (rapatriement des fichiers de code, récupération des dépendances…) (ici ce sera dans un serveur de test, mais cela sera fait ensuite dans un serveur de prod) et l’exécution d’analyses de qualité du code. Parmi ces analyses, une attention particulière est accordée aux tests automatisés, lesquels permettent de garantir que le code est stable et que le déploiement s’est correctement déroulé. Il s’agit d’un processus d’intégration continue indispensable dans l’évolution d’un projet. Voyons quelques solutions parmi d’autres (serveurs ci, analyseurs de code).

Travis

Fonctionnalités

Travis est un serveur d’intégration continue. Il va garantir que votre code est stable. C’est lui qui va builder votre projet pour ensuite exécuter vos tests sous les versions de PHP dont votre code assure la compatibilité.

Config

Travis demande un fichier de configuration à la racine du projet: .travis.yml. De base, ce fichier contiendra le langage du build, ainsi que ses versions (on peut donc tester la compatibilité du code avec plusieurs versions différentes, ainsi qu’avec hhvm):

language: php
php:
  - 5.6
  - 5.5
  - 5.4
  - hhvm

Il existe un outil de validation de ce fichier. Travis propose également un exemple de projet PHP, intéressant notamment pour la gestion des tests sous plusieurs DB.

Intégration

Travis est lancé depuis un hook de GitHub. Autrement dit, il va se déclencher automatiquement dès lors que GitHub reçoit un nouveau push de Git.

Fichiers versionnés

.travis.yml

Doc et tutos

Se lancer dans Travis avec la doc officielle, avec un tuto assez clair de sitepoint, ou avec un tuto vidéo.

Scrutinizer

Fonctionnalités

Scrutinizer est un outil complémentaire à Travis. Et plus particulièrement, il réalise des analyses de code et sort une estimation de la qualité de votre pojet, ainsi que le taux de couverture des tests. Par ailleurs, il propose, davantage comme Travis, d’exécuter des build du code.

  1. Code review automatisées
    • Analyse de la couverture des tests.
    • Analyse de la qualité du code.
  2. Intégration continue (service payant)

Config

Il existe plusieurs possibilités de configurer Scrutinizer. Je vous conseille de simplement placer un fichier de configuration situé à la racine du projet et donc versionné: .scrutinizer.yml. Il existe un éditeur en ligne pour configurer facilement les multiples options de ce fichier.

L’outil est vraiment puissant et assez facilement paramétrable. Par contre, la couverture de code doit se faire via un serveur distant (comme Travis par exemple) pour se passer du service payant de build.

Intégration

Scrutinizer est également lancé depuis un hook de GitHub. Tout se fait donc automatiquement.

D’autre part, les issues peuvent être transmises à GitHub pour un report centralisé.

Seul bémol, Scrutinizer est dépendant d’un service externe pour lancer les tests unitaires. Son lancement est donc conditionné au lancement parallèle d’un service comme Travis, sans quoi le build échouera faute d’avoir trouvé un rapport de test.

Fichiers versionnés

.scrutinizer.yml

Doc et tutos

Se lancer dans Scrutinizer avec la doc officielle.

SensioLabs Insight

Fonctionnalités

Insight est un outil d’analyse de code qui se targue de procéder également à des analyses dynamiques. Il est vrai que les analyses fournies semblent offrir des possibilités complémentaires aux outils vus précédemment.

Config

Insight peut également se configurer grâce à un fichier situé à la racine du projet : .insight.yml

Intégration

A nouveau, Insight est lancé depuis un hook de GitHub. Tout se fait donc automatiquement.

Comme Scrutinizer, les issues peuvent être transmises à GitHub.

Fichiers versionnés

.insight.yml

Doc et tutos

Se lancer dans Insight

Les gestionnaires de dépendances

A l’opposé du Syndrôme NIH ou du fameux « réinventer la roue », une application ne se conçoit pas comme un bloc monolithique, mais bien comme la somme d’une multitude de plugins. Votre code est destiné à constituer l’une de ces briques, et s’appuie lui-même sur une série de briques déjà écrites. Ce sont ses dépendances.

Un système de gestion de dépendances doit répondre à trois problématiques principales:

  • Un repository distant doit lister les librairies disponibles ainsi que leurs versions.
  • Un logiciel doit permettre de télécharger des librairies, en gèrant notamment les incompatibilités et les upgrade de versions.
  • Un système d’intégration doit permettre d’utiliser les librairies dans le code.

Composer

Composer est le gestionnaire de dépendance le plus utilisé pour l’instant dans le monde de PHP. Il a détrôné Pear grâce à sa simplicité d’utilisation. Composer répond à deux des problématiques décrites plus haut: il va télécharger les librairies externes selon une version spécifiée, et gérer leur intégration dans votre projet grâce à un autoloader.

Lister les dépendances

Composer se base sur un fichier de config composer.json qui répertorie les dépendances et leurs versions.

{
    "require": {
        "vendor/package": "2.*"
    }
}

Ce fichier est configurable en ligne de commande:

php composer.phar require vendor/package:2.*

De plus, selon votre environnement, vous pouvez demander le chargement de librairies spécifiques (require et require-dev).

Installer les dépendances

Une simple ligne de commande permet de télécharger les librairies listées dans votre fichier de config.

php composer.phar install

Composer les place dans le dossier vendor. Ce dossier ne doit dès lors pas être versionné, car il revient à Composer de s’occuper d’alimenter les dépendances lors du build du projet.

Gérer les versions

composer.lock est un fichier de lock de Composer. Il permet de freezer les versions exactes qui sont chargées lors de l’installation initiale des dépendances. Ce freeze contribue à garantir le comportement de l’application après son build, sur base du comportement tel que développé. C’est le processus qu’on privilégiera pour la mise en prod d’une application.

Ainsi, lors de la première installation d’une nouvelle dépendance, Composer ajoute la version téléchargée dans ce fichier. Lorsque l’on rebuildera le projet par la suite, l’installation des dépendances se fera sur base des versions précises telles qu’elles ont été ainsi répertoriées.

Les versions des dépendances peuvent toutefois être mises à jour via la commande update. Cette commande permet de récupérer la dernière version en date d’une librairie qui corresponde à la définition faite dans le fichier de config composer.json.

Attention, composer.lock n’a d’effet que pour le projet courant, et pas pour les projets dont il est dépendant. C’est pour cette raison que les librairies de dépendance ne vont pas forcément versionner ce fichier. A l’inverse, une application web doit absolument freezer ses dépendances pour assurer que le comportement de prod soit identique.

A noter toutefois que, malgré tout, Scrutinizer recommande de le versionner.

Loader les dépendances

Grâce aux PSR 0 et 4, Composer offre un autoloader des dépendances de votre projet. Il suffit d’inclure le fichier vendor/autoload.php. Nous verrons que ceci peut être facilement réalisé dans le fichier de configuration des tests (car au final, seuls les tests ont besoin, en développement, de ce fichier). Vos dépendances seront ainsi automatiquement chargées selon le principe d’autoloadage de PHP.

Par ailleurs, il vous est possible, et même recommandé, d’utiliser Composer pour autoloader vos propres classes. Une fois que votre projet sera lui-même une dépendance, l’application qui l’utilisera pourra ainsi charger votre code de la même sorte, via l’autoloader de Composer. Pour ce faire, vous devez simplement préciser le type de PSR utilisée par votre projet dans le fichier de config de Composer. Nous en verrons un peu plus dans notre prochain article sur les différences entre les deux systèmes de PSR.

{
    "autoload": {
        "psr-4": {"Acme\": "src/"}
    }
}

Lister les settings de PHP

Un autre très gros avantage de Composer est qu’il permet de lister les settings de PHP. A savoir:

  • Les versions de PHP/HHVM sous lesquelles tourne le package (ex: php >=5.3.2)
  • Les extensions/librairies PHP utilisées par le package (ex: ext-pdo ou lib-pcre)

Bien évidemment, Composer ne va pas aller installer une extension qui vous manquerait, mais il doit normalement vous signaler le problème.

{
    "require": {
        "php": ">=5.3.2",
        "ext-pdo": "*",
        "lib-pcre": "*"
    }
}

Config

La config de Composer est gérée directement dans le fichier composer.json. Il définit notamment les dépendances et leurs versions.

Le build de Travis est dépendant de Composer, et il est nécessaire de demander explicitement l’installation des dépendances dans son propre fichier de config:

before_script:
  - composer self-update
  - composer install

Le fichier vendor/autoload.php doit être inclus comme bootstrap de votre libraire, mais uniquement pour les tests. Par ailleurs, votre projet doit préciser le type PSR utilisée pour son propre autoloadage.

Fichiers versionnés

composer.json doit être absolument inclus.
composer.lock qui n’est pas nécessaire pour les librairies (mais l’est pour les app).
Le dossier vendor doit impérativement être exlu, car il sera reconstruit lors de chaque build.
composer.phar doit également être exclu, si jamais il est stocké, par facilité, à l’intérieur du projet.

Doc et tutos

Découvrir Composer avec la doc officielle, la doc pour les librairies, ou avec un tuto vidéo.
Une conférence sur les bonnes pratiques de Composer.

Packagist

Packagist est le pendant de Composer. C’est lui qui liste les librairies disponibles. (A noter qu’il est possible de se passer de Packagist depuis Composer en utilisant par exemple GitHub ou Toran Proxy). C’est ce qui permet de partager votre code. Dès lors que votre librairie est publiée sur GitHub, vous pouvez en préciser très facilement les différentes versions et les proposer au téléchargement de Composer via Packagist.

Intégration

Packagist fonctionne également en harmonie avec GitHub. Il suffit de rajouter une projet GitHub, ainsi qu’un système de hook pour que vos versions soient automatiquement disponibles.

Versions

Pour définir les versions téléchargeables, Packagist se base sur les tag git. Un tag est une version (c’est-à-dire un point dans le temps qui ne doit plus changer).

A noter que le numéro de vos versions ne doit par contre pas se trouver dans le fichier composer.json, car il interférera avec les tags Git.

GitHub vous permet de créer à la volée une version, en y associant une description. C’est la méthode la plus facile et la plus complète, selon moi.

Il est important de normaliser ses numéros de version selon la Semantic Versioning 2.0.0 (SemVer). Il s’agit (en simplifiant) d’un système essentiellement basé sur 3 nombres séparés par des points (par exemple "2.1.5") définissant de manière logique les modifications que peut subir un code:

  • Le premier numéro correspond à la version majeure. Un saut de version majeure implique des modifications dans votre API.
  • Le deuxième numéro correspond à la version mineure. Un saut de version mineure implique l’ajout de fonctionnalités, tout en assurant la rétrocompatibilité.
  • Le troisième numéro correspond à des patch apportés. Il s’agit de corrections de bug.

C’est sur cette base que Composer propose un système de pattern pour définir les dépendances de versions dans son fichier de config. Il est conseillé d’utiliser la contrainte de version « ~ » (Tilde Operator).

Enfin, un système de suffixe (alpha, patch, etc) peut être ajouté au numéro de version. Ces suffixes indiquent que la version n’est pas encore stable (dev -> alpha -> beta -> RC -> stable), et, par défaut, empêcheront qu’elle soit prise en considération par Composer.

Monitoring des dépendances

Il existe plusieurs services de monitoring des dépendances. L’idée est d’informer sur l’état des dépendances d’un projet.

Par exemple, VersionEye permet deux choses:

  • Comme Packagist, une vision sur les dépendances d’un projet. Mais, en plus, VersionEye indique (en se basant sur le fichier composer.lock) si ses dépendances sont à jour.
  • Un aperçu du nombre de librairies dépendantes.

Un autre exemple: Depending qui travaille spécifiquement avec Composer.

Conclusions

Les différents outils que nous avons vus se complètent tous pour offrir la possibilité d’installer un système de build automatique. C’est ce qu’on appelle l’intégration continue (il nous manque encore les tests automatiques que nous verrons bientôt). Cela se base sur un système de versionning (Git), un système de repository de code (GitHub), un système de gestion dépendances (Composer), un serveur d’analyse du code (Scrutinizer/Insight), ainsi qu’un serveur de build (Travis). Ces différents outils s’interconnectent facilement et se configurent assez rapidement.

Nous verrons bientôt l’organisation interne de notre package, des différents fichiers sources et tests.

Je me permets de rappeler que les bonnes pratiques décrites ici sont rassemblées dans un projet GitHub.

Enfin, n’hésitez pas à compléter cet article de vos commentaires! :-)

Une réflexion au sujet de « Bien débuter sa lib PHP: Part I – Les outils »

  1. Ping : Bien débuter sa lib PHP: Intro

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>