Introduction : deux camps, un seul combat
\n\nTout développeur PHP se retrouve un jour face à un dilemme : coder en style fonctionnel ou plonger dans l'univers des classes et des objets. C'est un peu comme choisir entre un couteau suisse et un multitool — les deux résolvent des problèmes, mais de manière différente. Dans cet article, nous allons décortiquer l'approche fonctionnelle vs orientée objet en PHP, analyser du code concret et déterminer quand utiliser chaque outil.
\n\nPHP est un langage unique. Né procédural, il a grandi avec la POO et, dans ses dernières versions (7.4+, 8.x), il intègre activement des fonctionnalités fonctionnelles : fonctions fléchées, closures, typage. Cela signifie que vous pouvez mélanger les approches. Mais comment ne pas s'y perdre ? C'est ce que nous allons voir.
\n\nLes bases : ce qui distingue ces deux mondes
\n\nL'approche fonctionnelle (Functional Programming)
\n\nIci, tout tourne autour des fonctions. Des fonctions pures, sans effets de bord, qui retournent toujours un résultat prévisible. Pas d'état global, pas de mutation de variables. Les données circulent en chaîne, comme sur un tapis roulant.
\n\n// Style fonctionnel : simple, prévisible\n$numbers = [1, 2, 3, 4, 5];\n\n$result = array_map(\n fn($n) => $n * 2,\n array_filter($numbers, fn($n) => $n % 2 === 0)\n);\n\nprint_r($result); // [4, 8]\n\nVous avez remarqué ? On ne modifie pas le tableau d'origine, on n'utilise pas de boucles. Tout est déclaratif : prendre les pairs, les doubler, les retourner. Cela fait gagner du temps en débogage — aucun effet de bord.
\n\nL'approche orientée objet (POO)
\n\nLa POO s'articule autour des objets — des entités qui stockent un état et un comportement. Les classes encapsulent les données, les héritiers étendent les fonctionnalités, le polymorphisme permet de changer la logique à la volée.
\n\n// Style POO : structure et réutilisabilité\nclass NumberProcessor {\n private array $numbers;\n\n public function __construct(array $numbers) {\n $this->numbers = $numbers;\n }\n\n public function getEvens(): array {\n return array_filter($this->numbers, fn($n) => $n % 2 === 0);\n }\n\n public function multiplyBy(int $factor): self {\n $this->numbers = array_map(fn($n) => $n * $factor, $this->numbers);\n return $this;\n }\n\n public function getResult(): array {\n return $this->numbers;\n }\n}\n\n$processor = new NumberProcessor([1, 2, 3, 4, 5]);\n$result = $processor->getEvens()->multiplyBy(2)->getResult();\nprint_r($result); // [4, 8]\n\nIci, nous avons créé un objet qui conserve un état. On peut enchaîner les méthodes. Avantage : si on veut ajouter une nouvelle opération, il suffit d'ajouter une méthode dans la classe.
\n\nQuand l'approche fonctionnelle est gagnante
\n\n1. Traitement de données sans effets de bord
\n\nImaginez que vous écriviez un analyseur de logs ou un convertisseur de devises. Les données circulent sur un tapis roulant : lire → filtrer → transformer → sauvegarder. Les fonctions sont ici idéales. Elles ne dépendent d'aucun état externe et sont faciles à tester.
\n\n2. Collections et tableaux
\n\nPHP propose des fonctions puissantes pour manipuler les tableaux : array_map, array_filter, array_reduce. Associées aux fonctions fléchées (PHP 7.4+), elles transforment le code en poésie.
$users = [\n ['name' => 'Anne', 'age' => 25],\n ['name' => 'Boris', 'age' => 17],\n ['name' => 'Vicky', 'age' => 30],\n];\n\n$adultNames = array_map(\n fn($user) => $user['name'],\n array_filter($users, fn($user) => $user['age'] >= 18)\n);\n\n// ['Anne', 'Vicky']\n\nPropre, lisible, sans classes. Pour des transformations simples, c'est le meilleur choix.
\n\n3. Tests sans mocks
\n\nLes fonctions n'ont pas d'état, donc elles sont faciles à tester. Pas besoin de créer des mocks ou des stubs complexes. Il suffit de passer des données et de vérifier le résultat.
\n\nQuand l'approche orientée objet est indispensable
\n\n1. Logique métier complexe avec état
\n\n