« Class ‘Stripe\StripeClient’ not found » — ce message n’est jamais apparu en production sur ce site, mais un profil Blackfire a mis en lumière un coupable plus discret : chaque requête HTTP passait un temps non négligeable à localiser les classes de l’extension de facturation avant même d’exécuter la moindre logique métier.
L’extension en question embarquait le SDK PHP de Stripe via Composer, avec plusieurs dizaines de dépendances transitives (le SDK Stripe lui-même, une bibliothèque HTTP, des utilitaires de sérialisation). Le profil montrait un temps cumulé anormalement élevé passé dans ComposerAutoloaderInit::loadClassLoader et dans les résolutions PSR-4 successives, avant même le premier hook WordPress.
Comment fonctionne l’autoloader PSR-4 par défaut
Composer génère, par défaut, un autoloader qui associe un espace de noms à un chemin de base, puis reconstruit dynamiquement le chemin du fichier à charger à partir du nom de classe demandé. Ce mécanisme est flexible — il tolère l’ajout de nouvelles classes sans régénération — mais il implique, à chaque appel non mis en cache, un test d’existence de fichier (file_exists() ou équivalent) potentiellement redondant si la classe n’est pas trouvée du premier coup.
Sur un système de fichiers réseau (montage NFS ou volume monté sur un hébergement mutualisé partagé), chaque appel stat() supplémentaire coûte bien plus cher que sur un disque local SSD, ce qui amplifie fortement ce type de surcoût.
Le diagnostic par Blackfire

Le profil Blackfire ventilait le temps d’initialisation de la requête ainsi : sur une page produit chargeant l’extension de facturation, environ 45 millisecondes étaient consommées avant le premier hook plugins_loaded, dont un peu plus de la moitié attribuable directement à la résolution de classes de l’extension Stripe et de ses dépendances. Un chiffre qui reste invisible dans une mesure de temps de réponse globale, mais qui pèse directement sur le Time To First Byte, mesuré avant même que le rendu HTML ne commence.
La régénération en mode classmap-authoritative
La commande suivante a permis de générer une carte de classes précompilée, associant directement chaque nom de classe à son chemin de fichier exact, sans passer par la résolution dynamique PSR-4 à l’exécution :
composer dump-autoload --optimize --classmap-authoritative --no-dev
Le drapeau --classmap-authoritative va plus loin que le simple --optimize : il indique à l’autoloader de considérer la classmap générée comme la source de vérité absolue, sans jamais retomber sur la résolution PSR-4 dynamique même si une classe semble manquante. Cela suppose une contrainte forte : toute classe chargée dynamiquement (via un include conditionnel non déclaré à Composer, par exemple) casserait le site plutôt que d’être simplement ignorée. Un audit rapide du code de l’extension a confirmé qu’aucune classe n’était chargée en dehors du mécanisme Composer standard.
Intégration dans le déploiement
La régénération de l’autoloader a été ajoutée à l’étape de déploiement, après l’installation des dépendances et avant la mise en production effective, afin que la classmap corresponde toujours exactement au code déployé :
composer install --no-dev --prefer-dist
composer dump-autoload --optimize --classmap-authoritative --no-dev
Les chiffres avant/après
| Mesure | Autoloader PSR-4 dynamique | Classmap authoritative |
|---|---|---|
| TTFB moyen (page produit) | 212 ms | 174 ms |
| Temps avant plugins_loaded | 45 ms | 7 ms |
| Appels file_exists() mesurés (profil Blackfire) | 612 | 0 |
L’écart de 38 millisecondes sur le TTFB moyen peut sembler anecdotique isolément, mais il s’applique à chaque requête non mise en cache de page, y compris les appels Ajax et les webhooks Stripe eux-mêmes, qui ne bénéficient jamais du cache de page.
Un piège à surveiller après coup
- Toute mise à jour de l’extension ou ajout d’une dépendance Composer sans régénération de la classmap authoritative peut réintroduire silencieusement des classes non résolues.
- Le mode classmap-authoritative doit être régénéré à chaque déploiement, jamais une seule fois manuellement en production.
- Un environnement de recette qui ne reproduit pas cette étape peut masquer une régression jusqu’à la mise en production.
Un autoloader n’est jamais un détail : c’est la toute première chose que chaque requête doit traverser, avant même de savoir ce qu’elle doit faire.
Pour aller plus loin
Ce type d’optimisation profite le plus aux sites qui embarquent de nombreuses dépendances Composer chargées tôt dans le cycle de requête : SDK de paiement, clients d’API tierces, bibliothèques de journalisation. Sur une extension avec seulement deux ou trois classes, le gain resterait proche de zéro. Le réflexe à retenir est de vérifier, via un profileur, si l’autoloader figure réellement dans le temps de réponse avant d’investir dans ce réglage.