Depuis maintenant plus d’un an, j’enseigne le PHP à des élèves d’une école digitale, aussi bien à des débutants qu’à des élèves confirmés. Je démarre tous mes cours par le partage de ces notions et la présentation d’un ensemble de bonnes pratiques.

Ce sont ces mêmes pratiques que nous avons mis en place en interne également chez Web and Cow. Chaque développeur qui rejoint l’équipe est invité à les consulter et à les respecter. C’est primordial pour que le code de chacun puisse être compréhensible et repris par tous.

Attention, d’une organisation à une autre, d’une entreprise à une autre, ces bonnes pratiques et conventions peuvent changer.

Ecriture

Les noms des variables, des fonctions, des méthodes et des attributs sont écrits en camelCase.

$maVariableNumerique = 3;
function sommeDesEntiers($maximum) {...}

Les noms des clés dans un tableau sont écrites en snake_case.

$user = [
   'username' => 'monadresse@mail.com',
   'first_name' => 'John',
   'last_name' => 'Doe',
   'active' => 1
];

Les noms des constantes sont écrits en MAJUSCULE

define('CHIFFRE_PORTE_BONHEUR', 13);

Les noms des objets sont écrits en PascalCase. Chaque objet est stocké dans un fichier qui porte le même nom que l’objet et ne contient que cet objet.

class Aventurier
{
...
}

En SQL, les tables et les noms des colonnes sont écrits en snake_case.

  • Nom de la table : users
  • Noms des champs (par exemple) :
    • id
    • username
    • password
    • first_name
    • last_name
    • created

Accolades et espaces

Les accolades sont à la ligne suivant la déclaration d’une classe, d’une fonction ou d’une méthode.

class Aventurier
{
    // Nom de mon Aventurier
    public $nom = '';
    
    // Constructeur
    public function __construct($nom)
    {
        $this->nom = $nom;
    }
}

Les accolades sont à la suite, précédée d’un espace, pour un if, switch, while, foreach, etc. et sont obligatoires.

function calculSommeNombresPairs($maximum)
{
    $somme = 0;
    for ($i = 1; $i <= $maximum; $i++) {
        if ($i % 2 == 0) {
            $somme += $i;   
        }
    }

    return $somme;
}

On ne met pas d’espace entre le nom d’une fonction et l’appel de ses paramètres. Même chose à la création d’un objet. Seul echo fait exception.

$maSomme = calculSommeNombresPairs(200);
echo $maSomme;

$monAventurier = new Aventurier('Actarus');
echo $monAventurier->getNom();

Respect du typage

PHP est souvent « trollé » pour le fait que le typage n’est pas du contraignant. Une variable peut en effet changer de type à tout moment. On peut alots sur forcer à respecter le typage, pour le contenu d’une variable mais aussi pour le retour d’une fonction.

Une fonction doit alors toujours retourner le même type de résultat. Si la fonction peut retourner plusieurs choses, favorisez un tableau en retour.

// Au lieu de faire
function trouvePairesDeValeurs($valeurs)
{
    // Je recherche 2 valeurs identiques dans un tableau de valeurs

    // Si j'en ai trouvé, je retourne la valeur de ces paires
    if ($pairesTrouves) {
        return $valeursPairesTrouvees;
    }

    return false;
}

// Préférez faire
function trouvePairesDeValeurs($valeurs)
{
    // Je recherche 2 valeurs identiques dans un tableau de valeurs
    
    // De cette manière ma fonction retourne toujours la même chose
    return [
        'paires_trouves' => $pairesTrouves,
        'valeurs_paires_trouvees' => $valeursPairesTrouvees
    ]; 
}

Un tableau ne doit contenir qu’un seul type d’informations. Si vous avez besoin de stocker plusieurs types d’informations, utilisez un tableau associatif :

// J'ai besoin de stocker les informations d'un utilisateur
// Evitez :
$utilisateur = [1, 'Arthur', 'Weill', 32, ['PHP', 'HTML', 'CSS', 'JS'], true];

// Préférez :
$utilisateur = [
    'id' => 1,
    'prenom' => 'Arthur',
    'nom' => 'Weill',
    'age' => 32,
    'competences' => ['PHP', 'HTML', 'CSS', 'JS'],
    'maitrise_cakephp' => true
];

Nommage explicite et utilisation de constantes

Les noms des variables, des fonctions, méthodes et classes doivent être le plus explicites possibles.

// Evitez absolument les abbréviations, qui laissent place à l'interprétation
// Pas bon :
$numUser;
// Bon :
$numeroTelephoneUser;

Favorisez les quotes simples aux doubles et favoriser la concaténation.

$prenom = 'Jean';
$piece = 'Cuisine';

$phrase = $prenom . ' est dans la ' . $piece;
// Au lieu de :
$phrase = "$prenom est dans la $piece";

Utilisez des constantes pour réaliser des comparaisons de nombre ou de chaines de caractères. Ce principe est très intéressant pour avoir un code beaucoup plus lisible. De plus, si vous faites une faute de frappe sur une constante, PHP déclenchera une erreur, alors que si vous faites une faute de frappe dans une chaine de caractères, PHP ne déclenchera pas d’erreur :

// Imaginons je teste le statut d'une commande
if ($commande['statut'] == 1) {
    // Certaines instructions
}

if ($commande['statut'] == 2) {
    // D'autres instructions
}

// Préférez : (en ayant défini les constantes préalablement bien sûr)
if ($commande['statut'] == ETAT_COMMANDE_EN_COURS) {
    // Certaines instructions
}

if ($commande['statut'] == ETAT_COMMANDE_PAYEE) {
    // D'autres instructions
}
// Imaginons cette fois-ci je teste la présence d'un langage dans un tableau de compétences
if (in_array('html', $competences)) {
    // Certaines instructions
}

// Le code ci-dessous n'est pas bon mais ne génère pas d'erreur :
if (in_array('hmtl', $competences)) {
    // Certaines instructions
}

// Alors qu'avec une constante, disons LANGAGE_HTML, ce code génère une erreur :
if (in_array(LANGAGE_HMTL, $competences)) {
    // Certaines instructions
}

Limiter le nombre de paramètres d’une fonction et favoriser des options

Imaginons que j’ai besoin de créer une fonction pour construire une balise <input … />. Les possibilités de personnalisation sont nombreuses : type, value, placeholder, etc.

Je peux donc créer une fonction qui aura autant de paramètres que de possibilités de personnalisation :

function input($name, $type = 'text', $value = '', $placeholder = '', $id = '', $required = false)
{
// Détails de ma fonction
}

// Je peux l'appeler de cette façon :
echo input('prenom');
echo input('age', 'number');

// Mais si je ne veux paramétrer que le placeholder, je me retrouve avec :
echo input('prenom', 'text', '', 'Entre votre prénom');

// Ou si je veux que l'âge soit obligatoire :
echo input('age', 'number', '', '', '', true);

On voit dans les 2 derniers exemples que la lisibilité de l’appel de la fonction n’est pas optimale. Si je devine à quoi corresponde les 2 premiers paramètres, les 3 suivants sont tous à  » et donc difficiles à comprendre. Même le true à la fin n’est pas intuitif.

L’idée est donc de limiter le nombre de paramètres à seulement ceux qui sont obligatoires et d’avoir un paramètre $options :

function input($name, $options = [])
{
    // Traitement de la value
    if (isset($options['value'])) {
        // Prise en considération de cette option
    }

    // Valeur par défaut pour le type
    $type = 'text';
    if (isset($options['type'])) {
        $type = $options['type'];
    }

}

// Lors de l'appel de ma fonction, en reprenant les exemples précédents, j'aurais donc :
echo input('prenom');
echo input('age', ['type' => 'number']);

echo input('prenom', ['placeholder' => 'Entre votre prénom']);
echo input('age', ['type' => 'number', 'required' => true]);

Les appels des fonctions sont donc ici beaucoup plus lisibles et compréhensibles. Il n’y a aucune interprétation possible sur les options qui sont gérées et pas besoin de retenir dans quel ordre les paramètres ont été indiqués dans la déclaration de la fonction.

5 étapes pour coder une fonction

Quand on code une fonction, on a tendance à la coder « du haut vers le bas », je vous propose ici de fonctionner différemment pour se poser les bonnes questions au bon moment et bien organiser sa réflexion et son développement :

  1. Le mot clé « function » obligatoire, c’est un bon début !
  2. Le nom de la fonction, en respectant l’écriture et s’assurer d’une bonne compréhension de son nom. Ne soyez pas avare de caractères, privilégiez la lisibilité
  3. Les paramètres. « Qu’est ce qui passe dans la fonction ? » Quelles sont les données travaillées ? Sont elles nécessaires ? Y a t-il des valeurs par défaut possibles ? Est ce que je peux travailler avec un tableau d’options ? (cf. point précédent).
  4. L’instruction « return ». On passe tout de suite à la fin de la fonction. « Qu’est ce qui sort de ma fonction ? » Quelles sont les informations que je vais retourner, de quel type, organisé(es) comment ?
  5. Coder la logique de la fonction. L’idée est donc de structurer la fonction au maximum, de coder « le début » et « la fin » et de finir donc par le « milieu ».

Ne pas se reposer sur la « magie » de PHP

Favorisez les comparaisons strictes pour améliorer la compréhension immédiate de votre code.

// Je ne peux tester dans un if que des booléens
if ($monBooleen) {
    // Aucun soucis ici   
}

// Si j'ai un nombre, un nombre d'occurence par exemple
if ($nbOccurences) {
    // PHP va considérer false si la valeur est 0, true sinon
    // La compréhension n'est pas optimale
}
// Favorisez :
if ($nbOccurences != 0) {
   // Plus compréhensible
}

// Si j'ai un tableau, un tableau de compétences par exemple
if ($competences) {
    // PHP va considérer false si le tableau est vide, true sinon
    // La compréhension n'est pas optimale
}
// Favorisez :
if (!empty($competences)) {
    // Plus compréhensible
}

Eviter les « else »

Eviter au maximum les « else ». Avec un peu de pratique, il est possible de se passer (presque) complètement des « else ». Notamment en travaillant avec return ou en changeant l’ordre de sa logique.

// Si on recherche un élément dans un tableau
function recherche($elementRecherche, $tableau)
{
    $elementTrouve = false;
    foreach ($tableau as $element) {
        if ($element == $elementRecherche) {
            $elementTrouve = true;
        }
    }

    return $elementTrouve;
}

// On peut simplifier de cette façon :
function recherche($elementRecherche, $tableau)
{
    foreach ($tableau 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;
}
// A l'intérieur d'une fonction, à la fin, on retrouve parfois ce genre de code :

if ($condition1 && ($condition2 || $condition3)) {
    return true;
} else {
    return false;
}

// On a vu précédemment que le else était inutile ici mais on peut avoir aussi directement :
return ($condition1 && ($condition2 || $condition3));

Un article complet au sujet de la suppression du « else » est en cours de rédaction pour vous présenter plus de cas pratiques.

Codes d’erreur

Quand on développe, il est important de travailler ses messages d’erreur, notamment pour avertir l’utilisateur de l’éventuel problème qu’il rencontre. Mais il est aussi important d’avoir des codes d’erreur dédiés aux développeurs. Pour cela, respectez la règle suivante : ne jamais avoir 2 fois le même message d’erreur.

L’idée est donc de créer des codes d’erreur uniques. De cette manière si un utilisateur (ou vous même) constatez un message d’erreur, vous saurez immédiatement d’où vient le problème.

Donc au lieu d’avoir simplement « Une erreur est survenue », ajoutez un code : « Une erreur est survenue. [Code : U001] ».

La première lettre peut correspondre au fichier dans lequel vous vous trouvez. Si je suis dans mon fichier Users.php, mes codes d’erreur commenceront par « U ». Ensuite, au fil de mon développement, chaque nouvelle erreur est incrémentée de 1.

On a donc quelque chose de plus efficace pour le développeur sans pour autant donner un mauvais rendu à l’utilisateur final.


Documentation du code

Pour chaque fonction, rédigez @params et @return à minima. Prenez le temps donc d’expliquer le détails des paramètres (type, valeurs possibles, rôles) et même chose pour la valeur de retour.

Chaque ligne complexe doit être commentée. N’hésitez pas à vous référer à mon article sur les bonnes manières de coder pour bien comprendre cette partie.


Conclusion

En respectant ces quelques points, vous vous assurez un code lisible et compréhensible, pour vous et vos collaborateurs.

N’hésitez pas à garder cet article sous la main pour vous y référer régulièrement. Il est possible que je le complète au fil du temps.