PHP 8.6 : Les Partial Function Application arrivent

L
Laravel Actu
5 min

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 avec new 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
Partager :

Ne manquez aucune actualité Laravel

Recevez les meilleurs articles et tutoriels directement dans votre boîte mail.

Pas de spam. Désinscription possible à tout moment.