Un ensemble minimal de pratiques PHP pour un code lisible
Un code propre n'est pas une religion - c'est la façon dont vous épargnez à votre futur moi (et à vos coéquipiers) toute confusion. Vous trouverez ci-dessous un ensemble de pratiques amicales qui rendent le code PHP plus prévisible et plus facile à maintenir.

⚡ Note : les exemples utilisent Laravel pour plus de clarté, mais les idées s'appliquent à n'importe quel framework, CMS, ou simple PHP.
1) PSR-1, PSR-4, PSR-12 : langage commun et prévisibilité
Pourquoi c'est important : une structure et un formatage cohérents éliminent le bruit. Les revues se concentrent sur la logique plutôt que sur les espaces et les accolades.
Comment l'adopter : activez phpcs et un correcteur automatique, configurez le chargement automatique de PSR-4 dans composer.json, alignez vous sur PSR-12.
Avant :
class usercontroller {function STORE($Req){return User::Create($Req->all());}}Après :
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
class UserController
{
public function store(Request $request): User
{
return User::create($request->all());
}
}2) SOLIDE sans fanatisme : se souvenir d'abord de l'ASR
Pourquoi c'est important : une classe devrait avoir une seule raison de changer. Couplage plus faible, tests plus faciles, refactors plus sûrs.
Piège typique : un "objet Dieu" qui s'occupe de la base de données, du courrier électronique, de la journalisation et de la validation.
Avant :
class UserManager {
public function register(array $data) {
$user = User::create($data);
Mail::to($user->email)->send(new WelcomeMail($user));
Log::info('User created', ['id' => $user->id]);
return $user;
}
}Après :
class UserService
{
public function __construct(
protected UserRepository $users,
protected Mailer $mailer,
protected Logger $logger,
) {}
public function register(array $data): User
{
$user = $this->users->create($data);
$this->mailer->sendWelcome($user);
$this->logger->userCreated($user);
return $user;
}
}3) L'encapsulation par défaut : soyez avare en éléments d'encapsulation public
Pourquoi c'est important : une surface publique plus petite protège votre API et garde les internes flexibles.
Avant : Après : Avant : Après : Avant : Après : Avant : Après : Après
class ReportGenerator {
public function connectDb() {/*...*/}
public function fetchData() {/*...*/}
public function renderReport() {/*...*/}
}Après :
class ReportGenerator {
protected function connectDb() {/*...*/}
protected function fetchData() {/*...*/}
public function renderReport() {/*...*/}
}4) Typage strict : tapez les paramètres et les retours
Pourquoi c'est important : moins de surprises, de meilleures indications de l'IDE, des refactors plus sûrs. Préférez les DTOs/objets de valeur aux tableaux libres.
Avant : Après : Avant : Après
public function calculate($a, $b) {
return $a + $b;
}Après :
public function calculate(int $a, int $b): int {
return $a + $b;
}5) ≤ 20 lignes par méthode : vérifiez les niveaux d'abstraction
Pourquoi c'est important : les méthodes longues mélangent souvent la validation, les règles du domaine, les effets de bord et les entrées-sorties.
Avant :
public function processOrder(array $data) {
// validate...
// create order...
// charge...
// email...
// log...
}Après : Avant : Après : Après : Après : Après : Après : Après : Après : Après : Après : Après :
public function processOrder(array $data) {
$this->validate($data);
$order = $this->createOrder($data);
$this->charge($order);
$this->notify($order);
$this->log($order);
}6) Duplication à plus de 2 endroits ? Extraire
Pourquoi c'est important : La méthode DRY réduit les dérives. Corriger une copie mais pas l'autre est une source classique de bogues.
Avant :
$user = User::create($data);
Mail::to($user->email)->send(new WelcomeMail($user));
$admin = User::create($adminData);
Mail::to($admin->email)->send(new WelcomeMail($admin));Après :
class UserService {
public function register(array $data): User {
$user = User::create($data);
Mail::to($user->email)->send(new WelcomeMail($user));
return $user;
}
}7) Référentiel + Service : contrôleurs légers, domaine clair
Pourquoi c'est important : séparer l'accès à la base de données (référentiels) des cas d'utilisation (services) rend le code explicable et testable.
Avant : Après
public function index()
{
return User::where('active', true)->get();
}Après :
class UserRepository {
public function active(): Collection {
return User::where('active', true)->get();
}
}
class UserService {
public function __construct(private UserRepository $users){}
public function getActive(): Collection { return $this->users->active(); }
}8) Comparaison stricte et conditions explicites
Pourquoi c'est important :=== évite les coercitions bizarres de PHP. N'utilisez if ($var) que pour les booléens garantis.
Avant : Après : Avant : Après
if ($user->age == '18') { /* ... */ }
if ($discount) { /* ... */ } // '0' is falsyAprès : Après : Après : Après : Après : Après : Après : Après : Après : Après : Après : Après :
if ($user->age === 18) { /* ... */ }
if ($discount !== null && $discount > 0) { /* ... */ }9) Nommage : optimisez l'attention du lecteur
Pourquoi c'est important : de bons noms sont de la documentation intégrée. Incluez les unités/formats lorsque c'est pertinent.
Avant : Après : Avant : Après
$amount = 100;Après : Après : Après : Après : Après : Après : Après : Après : Après : Après : Après : Après :
$orderTotalCents = 100;10) Promotion du constructeur PHP 8+
Pourquoi c'est important : moins d'éléments superflus, une intention plus claire.
final class CreateInvoice
{
public function __construct(
private CustomerRepository $customers,
private TaxCalculator $taxes,
) {}
public function handle(int $customerId, int $amountCents): Invoice { /*...*/ }
}11) Laravel Query Builder : utiliser des clauses conditionnelles
Pourquoi c'est important : éliminez les if-forêt autour des requêtes ; construisez-les de manière compositionnelle.
Avant :
$query = User::query();
if ($active) { $query->where('active', true); }
if ($role) { $query->where('role', $role); }
if ($fromDate) { $query->whereDate('created_at', '>=', $fromDate); }
$users = $query->get();Après :
$users = User::query()
->when($active, fn($q) => $q->where('active', true))
->when($role, fn($q) => $q->where('role', $role))
->when($fromDate, fn($q) => $q->whereDate('created_at', '>=', $fromDate))
->get();12) Mutations multiples de l'état de la base de données ? Enveloppez dans une transaction
Pourquoi c'est important : gardez la cohérence même si une étape échoue en plein vol.
Avant :
$order = Order::create($data);
$payment->charge($order->total);
$order->markPaid();Après :
DB::transaction(function () use ($data, $payment) {
$order = Order::create($data);
$payment->charge($order->total);
$order->markPaid();
});13) Retourner plus tôt avec des clauses de garde
Pourquoi c'est important : moins d'imbrication, plus facile à analyser, moins de branches else manquées.
Avant :
public function handle(?User $user) {
if ($user) {
if ($user->isActive()) {
// ...
}
}
}Après :
public function handle(?User $user) {
if (!$user || !$user->isActive()) {
return;
}
// main logic
}14) Évitez les vérités lorsque l'intention n'est pas claire
Pourquoi c'est important :if ($variable) cache l'ambiguïté des types ; soyez explicite pour les chaînes, les nombres et les tableaux.
Avant : Après : 14) Éviter la véracité lorsque l'intention n'est pas claire
if ($limit) { /* ... */ } // '0' becomes falseAprès :
if ($limit !== null) { /* ... */ }15) Automatisez pour que les habitudes ne se perdent pas
Pourquoi c'est important : les humains sont incohérents ; les outils ne le sont pas. Laissez l'automatisation contrôler le style et la sécurité.
- Pré-commission : fixeur + PHPCS + PHPStan/Psalm
- CI : mêmes vérifications + tests
- IDE templates/snippets pour les classes communes
- Laravel : exécutez Pint (
./vendor/bin/pint)
16) Des lignes directrices, pas des commandements
La vie réelle a des échéances, un héritage et des contraintes. Enfreignez les règles consciemment, laissez une note(pourquoi) et une tâche en attente(ce qu'il faut améliorer). L'objectif est la lisibilité et la prévisibilité, pas la pureté rituelle.
Contactez-nous
Besoin d’un audit externe de votre projet?
Faites-nous part de votre contexte et du résultat que vous souhaitez obtenir, et nous vous proposerons l'étape suivante la plus simple.