Conventions de codage : règles d'écriture

Dans un contexte ou une équipe de développeurs travaille sur des applications métiers PHP, il est important de vite mettre en place des règles de codages pour tous pour précisément permettre une meilleure relecture du code , une maintenance et une possibilité évolutivité de celui-ci.

Les exemples que nous prendrons ici seront basés sur le framework Symfony.

L'environnement de développement intégré Jetbrains PHPStorm signale déjà en rouge un certain nombre d'anomalies syntaxiques, sémantiques.

Ce framework PHP possède ses propres standards  et bonnes pratiques inspirés par les normes PSR-x créé par PHP-FIG (Le groupe de travail Framework Interoperability Group) qui s'occupe de normaliser les règles de codage.

Il a son propre outil qui permet de contrôler la qualité syntaxique, CsFixer basé lui-même sur PHP CSFixer et disponible ici https://cs.symfony.com/

Mais nous pouvons aussi utiliser dans l'équipe SonarLint qui est un excellent outil coupable à SonarQube https://www.sonarlint.org/

Pour uniformiser le code et permettre sa maintenabilité, sa lisibilité et faciliter la revue de code par l'équipe,

Il faut choisir les principes et les règles de codage à  appliquer et à savoir pour chaque membre de l'équipe.

Le but de cette section est donc de mettre en place un début de règles et de principes pour que le code soit compris et lisible par tous.

On va partir du plus général, au plus spécifique au langage PHP et au framework Symfony.

Attention :  Quand vous écrivez du code, gardez toujours en tête qu'il va être lu, amélioré, modifié par vos collègues, donc par d'autres humains, il faut donc toujours faire le maximum pour qu'il soit lisible et compréhensible.

Il  existe deux manières de concevoir un logiciel. La première, c’est de le faire si simple qu’il est évident qu’il ne présente aucun problème. La seconde, c’est de le faire si compliqué qu’il ne présente aucun problème évident. La première méthode est de loin la plus complexe

                                                                                                      C.A.R Hoare, inventeur de l'algorithme de tri rapide quicksort

Les règles d'écriture syntaxiques

 

Les règles exhaustives à suivre sont consignées dans les PSR disponibles ici https://www.php-fig.org/

 

Type d'élément

Exemple Règle à appliquer

Classe, Interface

class Voiture 
 {     ...
 }
PascalCase
Variable, fonction,méthode, attribut de classe
$nbPages = 3;
camelCase
 
nom des clés dans un tableau associatif, arguments d'appel API

$user = [

 'username' => 'GodFather',

 'first_name' => 'Mickael',

 'last_name' => 'Corleone',

 'active' => 1

];
 

snakeCase
 
Constantes
define('NB_PORTES', 13);
UpperCase

Nom des colonnes SQL
Nom de la table : users

Nom des champs : first_name last_name
SnakeCase

Nom des ID / Classes dans le HTML
 
<div id='titre-up'> <label class='label-form'> test </label></div>
Kebab Case ou Spinal Case

 

Indentation ( Accolades et espaces)

Fonction, méthode, classe, interface

Les accolades sont systématiquement à la ligne :

class User

{

 // Nom de mon utilisateur

 public $nom = '';


 // Constructeur

 public function __construct($nom)

 {

 $this->nom = $nom;

 }

}

 

Structures de contrôle :  if, switch, while, foreach

Les accolades sont à la suite, précédées d'un espace, elles sont obligatoires :

function calculSommeNombresPairs($maximum)

{

    $somme = 0;

    for ($i = 1; $i <= $maximum; $i++) {

        if ($i % 2 == 0) {

            $somme += $i; 

          }

    }

    return $somme;

}

Pas d’espace entre le nom d’une fonction et l’appel de ses paramètres. De même à l'instanciation d’un objet. Seul echo fait exception :

$monProduit = calculProduit(200);

echo $monProduit;

$maVoiture = new Voiture('Alpine');

echo $maVoiture->getNom();

 

Concaténation : Simple quote, double quote

 

De préférence, en cas de concaténation, mettre des simples quotes.

les développeurs ont tendance à utiliser un peu trop souvent les doubles quotes même quand ce n'est pas utile.

 

$nom = 'Antoine';

$langage = 'PHP';

// préférez 

$phrase = $nom . ' écrit du code ' . $langage;

// Au lieu de :

$phrase = "$nom écrit du code $langage";

 

Quelques règles pour les gouverner tous

Nom de paramètres à passer en argument d'une méthode, fonction

Passez maximum, cinq paramètres à une fonction. Si vous en avez plus, passer ceux qui sont obligatoires et pour le reste, créez un tableau d'options.

Attention : un tableau doit contenir un même type (int, string, boolean)  d'information, si vous devez en ajouter plusieurs, utiliser plutôt un tableau associatif plus approprié, voir une classe.

 

Bon exemple lisible

Mauvais exemple

function sommePremier($valeur, $options = [] ) { ...}
function sommeDesEntiers($valeurs, $primarité, 
$frequence, $puissance='') 
{
    ...
}

 

Constantes : quand est ce que ça sert ?

Les constantes peuvent aider à rendre le code beaucoup plus lisible, compréhensible , mais aussi maintenable.

Il permet notamment de ne modifier qu'à un seul endroit la valeur. Il est conseillé d'assigner la valeur dans la classe parente ou dans l'environnement fichier .env.

// Imaginons je teste le profil d'utilisateur Stargate

// Préférez : (en ayant défini les constantes préalablement bien sûr dans un .env)

if ($user->getProfil() === PROFIL_USER_RC) {

 // Certaines instructions

}

if ($user->getProfil() === PROFIL_USER_ADMIN) {

 // D'autres instructions

}

 

Note : L'opérateur "==" vérifie l'égalité entre les opérandes alors "===" vérifie en plus, l'égalité de type des deux opérandes.

Nous vous conseillons donc dans le doute de toujours mettre "===", car la valeur (string) "22" n'est pas toujours égale à l'entier 22 et peut provoquer certains effets de bords indésirés.

PHP étant un langage pas typé (typage dynamique), à la rigueur faiblement typé, il vaut mieux être précis quand on code.

En cas d'erreur, dans le nom de la constante PHP générera une erreur.

// Imaginons cette fois-ci je teste la présence d'un langage dans un tableau de compétences

if (in_array('php', $langages)) {

 // Certaines instructions

}

// Le code ci-dessous n'est pas bon mais ne génère pas d'erreur :

if (in_array('hpp', $langages)) {

 // Certaines instructions

}

// Alors qu'avec une constante, disons LANGAGE_PHP, ce code génère une erreur :

if (in_array(LANGAGE_HPP, $langage)) {

 // Certaines instructions

}

Une fonction, méthode doit toujours retourner le même type de résultat

// Au lieu de faire

function trouverNombresPremiers($nombres)

{

 // Je recherche des nombres premiers dans un tableau de valeurs

 // Si j'en ai trouvé, je retourne la valeur de ces premiers

 if ($premiersTrouves) {

 return $valeursPremiersTrouves;

 }

 // Sinon le booléen false

 return false;

}

// Préférez faire

function trouverNombresPremiers($nombres)

{

 // Je recherche des nombres premiers dans un tableau d'entiers

 

 // De cette manière ma fonction retourne toujours la même chose

 return [

 'premiers_trouves' => $premiersTrouves,

 'valeurs_premiers_trouves' => $valeursPremiersTrouvees

 ]; 

}

Dans le 1er cas , on retourne soit un tableau, en cas de succès, soit false.

Dans le 2ème cas, on retourne toujours un tableau , même vide.

Eviter les "else"

Avec un peu d'entrainement, on peut aisément se passer d'utiliser else, autant de fois qu'on s'en sert d'habitude.

Soit en revoyant l'ordre de sa logique dans notre algorithme.

Soit en utilisant l'instruction return à bon escient.

// Si on recherche un nombre paire dans un tableau d'entiers

function chercherPremier($elementRecherche, $valeurs)

{

 $elementTrouve = false;

 foreach ($valeurs as $element) {

 if ($element == $elementRecherche) {

 $elementTrouve = true;

 }

 }

 return $elementTrouve;

}

// On peut simplifier de cette façon :

function chercherPremier($elementRecherche, $valeurs)

{

 foreach ($valeurs as $element) {

 if ($element == $elementRecherche) {

 return true; // On a trouvé, on retourne true et la fonction se termine

 }

 }

 

 // Si on arrive là, c'est qu'on a pas trouvé l'élément

 return false;

}

Certains cas nécessitent une refactorisation du code ou un switch à la place des if/else imbriqués.

// A éviter autant que possible ce genre de choses dans une fonction

if ($pomme && ($orange || $ananas) {

    return false;

} else {

    return true;

}

// On peut mettre directement 

return (($pomme && ($orange || $ananas));

// De plus, on peut éviter les if imbriqué à plus de deux ou trois niveaux d'imbrications, il faut penser à switch qui est très peu utilisé

if ($un) {

    if ($trois == 1) {

 return $a;

 } else {

 return $b;

 }

}else{

 return c;

}

    

Codes d'erreur

Une des choses importantes qu'on omet souvent en écrivant un programme est de perfectionner la gestion des messages d'erreur pour prévenir l'utilisateur d'un souci auquel il fait face pendant qu'il interagit avec la fonctionnalité en cours d'utilisation.

Mais plus loin, pour ses collègues développeurs, support qui vont devoir corriger les bugs derrière nous.

Pourquoi ?

Tant que le code qu'on écrit est "fonctionnel", c'est-à-dire qu'il répond au besoin initial, le côté ergonomie utilisateur est souvent laissé pour compte.

On en revient donc à marteler qu'il faut toujours se mettre dans la peau de ses collègues et de ses utilisateurs finaux ( ceux qui vont se servir du programme qu'on écrit).

Pensons donc toujours à cibler deux types de public :

  • Les utilisateurs finaux , on parle de d'ergonomie UX (User eXperience)
  • Les collègues développeurs, support, testeurs, MOA, project Owner, on parle de DX (Developer eXperience)

Solutions

Jamais deux fois le même code d'erreur dans le même programme.

Ce principe permet  de savoir tout de suite quand le code d'erreur est unique de trouver le problème plus rapidement.

C'est par exemple le cas dans les retours de webservice SOAP ou d'API Rest.

Exemple : "Une erreur est survenue. [Code :  U001]"

La première lettre peut correspondre au fichier dans lequel on se trouve. Par exemple:  Users.php

Mettez un maximum d'indications avec le code d'erreur

Par exemple : "Une erreur est survenue lors de l'appel SOAP. Le paramètre $codePostal est incorrect.[ Code : F019]"

Documenter le code

 

Fonction, méthodes

Au minimum, @params et @return. Et expliquer simplement les paramètres et valeur de retour (types, valeurs possibles , rôles) comme dans la documentation de PHP par exemple

Instruction complexes ou ambiguës

Si une ligne vous parait difficile à lire , comprendre, ajouter un commentaire en français  pour éclairer

C'est une première brique pour obtenir une documentation technique de l'application.

 

DRY, Don't Repeat Yourself

Ce principe de développement logiciel, veut qu'on ne répète pas son code.

Nous nous attellerons à ne pas répéter plus de deux fois notre code.

Restez informés sur notre actualité

Inscrivez-vous à notre newsletter pour recevoir les dernières évolutions de notre produit