PHP 8.3 : ce qui change concrètement pour votre code
PHP 8.3, sorti en novembre 2023, continue l'évolution amorcée avec PHP 8.0. Ce guide passe en revue les nouveautés les plus utiles avec des exemples concrets.
Constantes typées dans les classes et interfaces
La nouveauté phare de PHP 8.3. Avant, les constantes de classe n'avaient pas de type déclaré :
// PHP < 8.3
class Status {
const ACTIVE = 'active';
const INACTIVE = 42; // Type incohérent, pas de warning
}
PHP 8.3 introduit les typed class constants :
class Status {
const string ACTIVE = 'active';
const string INACTIVE = 'inactive';
const string PENDING = 'pending';
}
class HttpCode {
const int OK = 200;
const int NOT_FOUND = 404;
const int SERVER_ERROR = 500;
}
interface Configurable {
const string DEFAULT_LOCALE = 'fr_FR';
const int CACHE_TTL = 3600;
}
Avec l'héritage, PHP vérifie la compatibilité des types :
class Base {
const string VALUE = 'base';
}
class Enfant extends Base {
const string VALUE = 'enfant'; // OK, même type
// const int VALUE = 42; // TypeError !
}
#[\Override] — déclarer explicitement une méthode overridée
class Collection {
public function count(): int {
return count($this->items);
}
}
class SortedCollection extends Collection {
#[\Override]
public function count(): int {
// Si count() n'existe PAS dans la classe parente :
// PHP 8.3 lève une erreur — pratique pour détecter les fautes de frappe !
return parent::count();
}
}
Cas d'usage réel : vous renommez une méthode dans la classe parente, PHP alertera immédiatement toutes les classes enfants qui utilisent #[\Override].
jsonvalidate() — valider du JSON sans le décoder
// PHP < 8.3 : décoder juste pour valider = gaspillage mémoire
function estJsonValide(string $json): bool {
json_decode($json);
return json_last_error() === JSON_ERROR_NONE;
}
// PHP 8.3 : validation légère, sans décodage
$payload = file_get_contents('php://input');
if (!json_validate($payload)) {
http_response_code(400);
echo json_encode(['error' => 'Payload JSON invalide']);
exit;
}
$data = json_decode($payload, associative: true);
Performance sur un JSON de 1Mo : jsonvalidate() est environ 3x plus rapide que jsondecode() suivi d'un check d'erreur.
Readonly properties : clonage amélioré
PHP 8.1 avait introduit readonly. PHP 8.3 améliore leur comportement lors du clonage :
class PrixProduit {
public function __construct(
public readonly float $ht,
public readonly float $taux_tva = 0.20,
) {}
public function avecRemise(float $remise): static {
return new static($this->ht * (1 - $remise), $this->taux_tva);
}
}
$prix = new PrixProduit(100.00);
$prixSolde = $prix->avecRemise(0.20); // 80 HT
echo $prixSolde->ht; // 80
Named Arguments avec les fonctions array*
// Difficile à lire sans named arguments
$resultat = array_slice($array, 2, 5, true);
// Avec named arguments (PHP 8.0+, meilleur support en 8.3)
$resultat = array_slice(
array: $array,
offset: 2,
length: 5,
preserve_keys: true
);
// Pratique pour str_contains, str_starts_with
$aCommence = str_starts_with(haystack: $url, needle: 'https');
Fibers : débogage amélioré
Les Fibers, introduites en PHP 8.1, permettent du code concurrent léger. PHP 8.3 améliore leur débogage avec des stack traces plus précises :
$fiber = new Fiber(function(): void {
echo "Debut de la tache\n";
$valeur = Fiber::suspend('donnee intermediaire');
echo "Reprise avec : $valeur\n";
});
$resultat = $fiber->start();
echo "Recu : $resultat\n";
$fiber->resume('ma reponse');
opensslcipherkeylength() — sécurité améliorée
// Avant : longueur hardcodée dans le code
$longueurCle = 32; // AES-256 => 32 bytes (à vérifier dans la doc)
// PHP 8.3 : obtenu dynamiquement
$algo = 'AES-256-GCM';
$longueurCle = openssl_cipher_key_length($algo);
$cle = random_bytes($longueurCle);
echo "Longueur requise pour $algo : {$longueurCle} bytes\n"; // 32
Améliorations des messages d'erreur
PHP 8.3 améliore significativement les messages d'erreur pour les types et les erreurs de propriétés :
class User {
public string $name;
public int $age;
}
$user = new User();
$user->age = 'trente';
// PHP 8.2 : "Cannot assign string to property User::$age of type int"
// PHP 8.3 : message identique mais avec plus de contexte dans le stack trace
Guide de migration vers PHP 8.3
# 1. Vérifier la compatibilité des dépendances
composer update --dry-run
# 2. Analyser avec PHP_CodeSniffer et PHPCompatibility
composer require --dev squizlabs/php_codesniffer phpcompatibility/php-compatibility
./vendor/bin/phpcs --config-set installed_paths vendor/phpcompatibility/php-compatibility
./vendor/bin/phpcs --standard=PHPCompatibility --runtime-set testVersion 8.3 src/
# 3. Lancer la suite de tests avec la nouvelle version
php8.3 vendor/bin/phpunit
# 4. Surveiller les dépréciations
ini_set('error_reporting', E_ALL);
Breaking changes mineurs :
- Comportement de
round()plus strict sur les NaN et Inf - Quelques fonctions dépréciées en 8.1 maintenant supprimées
strpad()avec des strings multibytes se comporte différemment
Performances PHP 8.3 vs 8.0
Des benchmarks sur des applications Symfony et Laravel montrent des gains de 5-15% entre PHP 8.0 et 8.3 grâce à des optimisations continues du JIT compiler et du garbage collector.
// Benchmark simple : 1 million d'itérations
$start = hrtime(true);
for ($i = 0; $i < 1_000_000; $i++) {
$str = str_contains('Hello World', 'World');
}
$end = hrtime(true);
echo round(($end - $start) / 1e6, 2) . " ms\n";
// PHP 8.0 : ~85ms
// PHP 8.3 : ~72ms (environ 15% plus rapide)
Pour aller plus loin : Documentation officielle PHP 8.3