POO : la POO en JavaScript, Python et PHP
Les concepts de la POO (classe, encapsulation, héritage, polymorphisme) sont les mêmes d’un langage à l’autre, mais la syntaxe et certaines règles changent. Cette page compare les langages abordés dans ce site.
Une même classe, trois langages
Section intitulée « Une même classe, trois langages »TypeScript
Section intitulée « TypeScript »class Compte { #solde = 0;
constructor( public readonly titulaire: string, soldeInitial = 0, ) { this.#solde = soldeInitial; }
deposer(montant: number): void { if (montant <= 0) throw new RangeError('montant invalide'); this.#solde += montant; }
get solde(): number { return this.#solde; }}class Compte: def __init__(self, titulaire: str, solde_initial: float = 0) -> None: self.titulaire = titulaire self._solde = solde_initial # _ : convention « privé »
def deposer(self, montant: float) -> None: if montant <= 0: raise ValueError("montant invalide") self._solde += montant
@property def solde(self) -> float: return self._solde
compte = Compte("Alice", 100)compte.deposer(50)print(compte.solde)<?phpdeclare(strict_types=1);
final class Compte{ private float $solde;
public function __construct( public readonly string $titulaire, float $soldeInitial = 0, ) { $this->solde = $soldeInitial; }
public function deposer(float $montant): void { if ($montant <= 0) { throw new InvalidArgumentException('montant invalide'); } $this->solde += $montant; }
public function solde(): float { return $this->solde; }}
$compte = new Compte('Alice', 100);$compte->deposer(50);echo $compte->solde(), "\n";Tableau comparatif
Section intitulée « Tableau comparatif »| Notion | TypeScript / JavaScript | Python | PHP |
|---|---|---|---|
| Définir une classe | class A {} |
class A: |
class A {} |
| Constructeur | constructor(...) |
__init__(self, ...) |
__construct(...) |
| Instance courante | this |
self (paramètre explicite) |
$this |
| Créer un objet | new A() |
A() |
new A() |
| Attribut privé | #champ (réel) ; private (compilation) |
_champ (convention), __champ (renommage) |
private (réel) |
| Attribut protégé | protected (TypeScript) |
_champ (convention) |
protected |
| Lecture seule | readonly (TypeScript) |
@property sans setter, dataclass(frozen=True) |
readonly |
| Méthode statique | static m() |
@staticmethod, @classmethod |
static function m() |
| Héritage | extends |
class B(A): |
extends |
| Appel du parent | super(...), super.m() |
super().m() |
parent::m() |
| Héritage multiple | Non (interfaces, mixins) | Oui (MRO) | Non (interfaces, traits) |
| Interface | interface (typage structurel) |
Protocol, classes abstraites |
interface |
| Classe abstraite | abstract class |
abc.ABC + @abstractmethod |
abstract class |
| Redéfinition vérifiée | override |
@override (module typing, Python 3.12) |
attribut #[\Override] (PHP 8.3) |
| Typage | Statique (compilation) | Facultatif (annotations, outils externes) | Types déclarés vérifiés à l’exécution |
JavaScript : les prototypes derrière les classes
Section intitulée « JavaScript : les prototypes derrière les classes »En JavaScript, class est une syntaxe sur un mécanisme de prototypes : chaque objet pointe vers un prototype dont il hérite les méthodes.
class Animal { constructor(nom) { this.nom = nom; } parler() { return `${this.nom} fait du bruit`; }}
console.log(typeof Animal); // 'function'console.log(Object.getPrototypeOf(new Animal('x')) === Animal.prototype); // trueConséquences : une méthode est partagée par toutes les instances (sur le prototype), this dépend de l’appel (voir Classes et objets), et on peut créer des objets sans classe (littéraux, Object.create). Les fonctions fabriques et les fermetures offrent une encapsulation sans classe :
function creerCompteur() { let n = 0; // privé par fermeture return { incrementer: () => ++n, valeur: () => n, };}Python : particularités
Section intitulée « Python : particularités »from abc import ABC, abstractmethodfrom dataclasses import dataclass
class Forme(ABC): @abstractmethod def aire(self) -> float: ...
class Cercle(Forme): def __init__(self, rayon: float) -> None: self.rayon = rayon
def aire(self) -> float: return 3.141592653589793 * self.rayon**2
@dataclass(frozen=True)class Point: # classe de données immuable x: float y: float
def __str__(self) -> str: return f"({self.x}, {self.y})"| Particularité | Détail |
|---|---|
| Pas de vraie confidentialité | _x est une convention, __x renomme sans interdire l’accès |
| Méthodes spéciales | __str__, __repr__, __eq__, __len__, __iter__… personnalisent le comportement |
@dataclass |
Génère __init__, __repr__, __eq__ pour des classes de données |
| Typage structurel | typing.Protocol |
| Canard typé (« duck typing ») | Un objet convient s’il a les méthodes attendues, sans interface déclarée |
Voir Python : premiers pas et Python : qualité et tests.
PHP : particularités
Section intitulée « PHP : particularités »<?phpdeclare(strict_types=1);
interface Notificateur{ public function envoyer(string $destinataire, string $message): void;}
trait Journalisable{ private array $journal = [];
public function noter(string $ligne): void { $this->journal[] = $ligne; }}
final class NotificateurCourriel implements Notificateur{ use Journalisable;
public function envoyer(string $destinataire, string $message): void { $this->noter("courriel à $destinataire"); }}| Particularité | Détail |
|---|---|
trait |
Réutilise du code dans plusieurs classes sans héritage (comparable à un mixin) |
final |
Interdit l’héritage ou la redéfinition |
| Promotion des propriétés du constructeur | public function __construct(public readonly string $nom) |
enum (PHP 8.1) |
Énumérations typées, avec méthodes |
| Méthodes magiques | __toString, __get, __call… (à utiliser avec modération) |
| Typage | Déclarations de types vérifiées à l’exécution avec declare(strict_types=1) |
Voir PHP : premiers pas.
Emprunter les bonnes idées
Section intitulée « Emprunter les bonnes idées »| Idée | Où elle est née | Utile partout |
|---|---|---|
| Interfaces pour découpler | TypeScript, PHP, Java | Oui |
| Objets-valeur immuables | dataclass(frozen=True), readonly |
Oui |
| Injection de dépendances par le constructeur | Tous | Oui |
override explicite |
TypeScript, PHP, Python 3.12 | Oui |
| Enums plutôt que chaînes magiques | TypeScript (unions), PHP, Python | Oui |
Programmation fonctionnelle et POO
Section intitulée « Programmation fonctionnelle et POO »La POO n’est pas la seule approche. En JavaScript, TypeScript et Python, un mélange est courant : des fonctions pures pour les calculs, des objets pour l’état et les ressources (connexions, caches), des types pour les données. Choisir selon le problème :
| Besoin | Approche |
|---|---|
| Transformer des données | Fonctions pures, map/filter/reduce |
| Maintenir un état et ses invariants | Classe |
| Variantes interchangeables d’un comportement | Interface + implémentations, ou fonctions passées en paramètre |
| Données sans comportement | Objets simples typés |
Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
self oublié en Python (TypeError: … takes 1 positional argument but 2 were given) |
Premier paramètre de chaque méthode d’instance : self |
this indéfini en JavaScript |
Méthode détachée de l’objet |
| Attribut « privé » Python modifié de l’extérieur | Convention seulement : utiliser @property et documenter |
Cannot instantiate abstract class (Python ou PHP) |
Implémenter toutes les méthodes abstraites |
| Héritage multiple Python au comportement surprenant | Consulter Classe.__mro__ (ordre de résolution) ; préférer la composition |
Fatal error: Cannot override final method (PHP) |
Méthode ou classe final |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Les versions des langages fournies par Ubuntu diffèrent (Python 3.12 ou 3.14, PHP 8.3 ou 8.5 : voir Python : installation et PHP : installation) ; certaines fonctions de POO récentes (@override de Python, #[\Override] de PHP) en dépendent.