Aller au contenu

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.

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)
<?php
declare(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";
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

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); // true

Consé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,
};
}
from abc import ABC, abstractmethod
from 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
declare(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.

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

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
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.