La version de PHP 8.6 à venir apporte une nouvelle fonctionnalité majeure : la Partial Function Application (PFA). Cette syntaxe permet de créer des closures préconfigurées en remplaçant certains arguments par des placeholders. Une approche qui réduit le boilerplate et améliore la lisibilité du code.
Qu’est-ce que la Partial Function Application ?
La Partial Function Application consiste à appeler une fonction avec seulement une partie de ses arguments, en utilisant des placeholders pour les valeurs manquantes. PHP retourne alors une closure qui attend les arguments restants.
La RFC a été approuvée à l’unanimité (33 voix pour, 0 contre) le 5 décembre 2025. Elle est actuellement en cours d’implémentation pour PHP 8.6.
Deux placeholders à retenir
?: représente exactement un argument manquant...: représente tous les arguments restants
Syntaxe de base
Voici le principe fondamental. Au lieu d’écrire une arrow function complète :
function calculate_price(float $amount, float $tvaRate): float
{
return $amount * (1 + $tvaRate);
}
// Approche classique avec arrow function
$withTva = fn(float $amount): float => calculate_price($amount, 0.20);
Vous pouvez désormais écrire :
function calculate_price(float $amount, float $tvaRate): float
{
return $amount * (1 + $tvaRate);
}
// Avec Partial Function Application en PHP 8.6
// Le ? indique que cet argument sera fourni plus tard
$withTva = calculate_price(?, 0.20);
// Utilisation
$withTva(100); // Retourne 120.0
$withTva(50); // Retourne 60.0
Le placeholder ? génère automatiquement une closure avec la signature appropriée.
Utilisation avec plusieurs placeholders
Chaque ? devient un paramètre de la closure résultante, dans l’ordre de lecture :
function format_user(string $firstName, string $lastName, string $title): string
{
return $title . ' ' . $firstName . ' ' . $lastName;
}
// Deux placeholders = deux paramètres dans la closure
$formatDoctor = format_user(?, ?, 'Dr.');
// La closure attend maintenant deux arguments
$formatDoctor('Jean', 'Dupont'); // "Dr. Jean Dupont"
$formatDoctor('Marie', 'Martin'); // "Dr. Marie Martin"
Le placeholder variadique ...
Le placeholder ... capture tous les arguments restants :
function log_event(
string $channel,
string $level,
string $message,
array $context = []
): void {
// Logique de logging...
}
// Fixe les deux premiers arguments, les autres restent flexibles
$appInfo = log_event('app', 'info', ...);
// Utilisation
$appInfo('Utilisateur connecté', ['user_id' => 42]);
$appInfo('Paiement effectué', ['amount' => 99.90]);
Cas d’usage avec Laravel
La PFA s’intègre naturellement dans l’écosystème Laravel, notamment avec les collections et les callbacks.
Transformation de collections
use Illuminate\Support\Collection;
// Fonction de formatage de prix
function format_price(float $price, string $currency, int $decimals): string
{
return number_format($price, $decimals) . ' ' . $currency;
}
$products = collect([29.99, 149.50, 9.99]);
// Création d'un formateur euro préconfiguré
$euroFormatter = format_price(?, 'EUR', 2);
// Application sur la collection
$formattedPrices = $products->map($euroFormatter);
// Collection: ["29.99 EUR", "149.50 EUR", "9.99 EUR"]
Validation et filtrage
// Vérification d'appartenance à une liste
$allowedRoles = ['admin', 'editor', 'moderator'];
$users = collect([
['name' => 'Alice', 'role' => 'admin'],
['name' => 'Bob', 'role' => 'guest'],
['name' => 'Charlie', 'role' => 'editor'],
]);
// Partial application de in_array avec le tableau autorisé
$hasAllowedRole = in_array(?, $allowedRoles, strict: true);
$authorizedUsers = $users->filter(
fn($user) => $hasAllowedRole($user['role'])
);
Combinaison avec le pipe operator
PHP 8.5 a introduit le pipe operator (|>). La PFA le complète naturellement :
// Traitement de données avec pipe et PFA
$result = $inputData
|> array_filter(?, fn($item) => $item->isActive())
|> array_map(strtoupper(...), ?)
|> implode(', ', ?);
Exécution différée (Thunk)
En fournissant tous les arguments avec ... à la fin, vous créez une closure sans paramètre qui exécute l’appel ultérieurement :
function send_notification(int $userId, string $message): void
{
// Envoi de notification...
}
// Création d'un "thunk" - tous les arguments sont fournis
$notifyAdmin = send_notification(1, 'Rapport généré', ...);
// L'appel n'est pas encore effectué
// ...
// Exécution différée
if ($reportReady) {
$notifyAdmin(); // Maintenant la notification est envoyée
}
Points d’attention
- Pas de PFA sur
new: L’instanciation avecnew Class(?, ...)n’est pas supportée. Utilisez une méthode factory statique. - Évaluation immédiate des arguments fixes : Les valeurs fournies sont évaluées au moment de la création de la partial, pas lors de l’appel.
- Ordre des placeholders nommés : Les placeholders nommés adoptent l’ordre dans lequel ils sont déclarés, permettant de réorganiser les paramètres.
// Exemple de réorganisation des paramètres
function connect(string $host, int $port, string $user): PDO
{
// Connexion...
}
// L'ordre des placeholders nommés définit l'ordre des paramètres
$localConnect = connect(user: ?, port: 3306, host: '127.0.0.1');
// La closure attend maintenant seulement $user
$pdo = $localConnect('root');
Résumé
La Partial Function Application de PHP 8.6 offre :
- Une syntaxe concise avec
?et...pour créer des closures - La réduction du boilerplate comparé aux arrow functions
- Une intégration fluide avec les callbacks et le pipe operator
- Le support complet de la réflexion et du typage
Cette fonctionnalité s’inscrit dans l’évolution fonctionnelle de PHP, aux côtés des First-class callables (PHP 8.1) et du pipe operator (PHP 8.5).
Ressources
À propos de Laravel Actu
Développeur passionné par Laravel et son écosystème.
Voir tous les articles