Passer au contenu principal

Qu’est-ce que le trait ForwardsCalls

Illuminate\Support\Traits\ForwardsCalls est un trait qui mutualise la délégation d’appels de méthodes vers un autre objet. Dans le cœur de Laravel, il est utilisé par les « objets wrappers » comme Eloquent ou Mail.
L’implémentation se trouve dans src/Illuminate/Support/Traits/ForwardsCalls.php. Lorsqu’une méthode inexistante est transférée, l’exception BadMethodCallException est reformatée pour inclure le nom de la classe appelante et relancée.

API de base

forwardCallTo($object, $method, $parameters)

Transfère directement une méthode à l’objet spécifié. Typiquement appelé depuis __call().

forwardDecoratedCallTo($object, $method, $parameters)

À utiliser quand un Builder ou un Decorator veut préserver le chaînage. Si la valeur de retour de la méthode ciblée est « l’objet de destination lui-même », elle est remplacée par « l’objet appelant ($this) » avant d’être retournée.

Combinaison avec __call() / __callStatic()

ForwardsCalls ne fournit pas de méthodes magiques. Vous implémentez __call() (et si besoin __callStatic()) dans votre classe et vous y appelez les méthodes forwardCallTo....

Exemples d’utilisation réels (interne à Laravel)

1

Les Facades fournissent un static proxy

Illuminate\Support\Facades\Facade délègue directement à l’instance racine via __callStatic(). Les facades étant des appels statiques, elles utilisent une délégation directe et non ForwardsCalls.
2

Eloquent Builder utilise forwardCallTo

Illuminate\Database\Eloquent\Builder::__call() transmet les méthodes non résolues au Query Builder interne via forwardCallTo($this->query, ...), puis retourne $this en fin de traitement pour préserver la chaîne fluide.
3

Relation / Mail / Event utilisent forwardDecoratedCallTo

Illuminate\Database\Eloquent\Relations\Relation, Illuminate\Mail\Message et Illuminate\Events\NullDispatcher utilisent forwardDecoratedCallTo : ils délèguent à l’objet interne tout en préservant le chaînage de l’API externe.

Implémentation de base d’un proxy (forwardCallTo)

use Illuminate\Support\Traits\ForwardsCalls;

class CourierProxy
{
    use ForwardsCalls;

    public function __construct(
        protected CourierDriver $driver
    ) {}

    public function __call(string $method, array $parameters): mixed
    {
        return $this->forwardCallTo($this->driver, $method, $parameters);
    }
}
Ainsi, CourierProxy expose de façon transparente l’API publique de CourierDriver.

Proxy compatible chaînage (forwardDecoratedCallTo)

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Traits\ForwardsCalls;

class QueryProxy
{
    use ForwardsCalls;

    public function __construct(
        protected Builder $query
    ) {}

    public function __call(string $method, array $parameters): static
    {
        $this->forwardDecoratedCallTo($this->query, $method, $parameters);

        return $this;
    }

    public function get(): \Illuminate\Support\Collection
    {
        return $this->query->get();
    }
}
$users = (new QueryProxy(User::query()))
    ->where('active', true)
    ->orderByDesc('created_at')
    ->limit(10)
    ->get();
Plutôt que d’écrire manuellement return $this, utilisez la règle de forwardDecoratedCallTo (« si la valeur de retour est l’objet de destination lui-même, le remplacer par $this »), c’est plus sûr.

Lancement automatique de BadMethodCallException

Lorsqu’une méthode inexistante est appelée, ForwardsCalls relance une BadMethodCallException avec le nom de la classe appelante.
try {
    (new CourierProxy($driver))->missingMethod();
} catch (\BadMethodCallException $e) {
    // Ex. : Call to undefined method App\Services\CourierProxy::missingMethod()
    report($e);
}
L’utilisateur peut ainsi identifier immédiatement « dans quelle API externe l’échec est survenu ».

Comparaison avec Macroable

AspectMacroableForwardsCalls
ObjectifAjouter de nouvelles méthodes à une classe existanteDéléguer des méthodes à un autre objet
Points d’entrée principauxmacro(), mixin()forwardCallTo(), forwardDecoratedCallTo()
Cas appropriéExtension d’APIProxy / Decorator / Adapter
Utiliser ForwardsCalls pour « ajouter des méthodes » aboutit à des échecs systématiques pour les méthodes que la cible ne possède pas. Si votre but est d’étendre une API, choisissez Macroable.

Exemples d’utilisation dans le développement de packages

1) Manager qui bascule entre plusieurs Drivers

use Illuminate\Support\Traits\ForwardsCalls;

class SmsManager
{
    use ForwardsCalls;

    public function __construct(
        protected SmsDriver $driver
    ) {}

    public function via(string $name): static
    {
        $this->driver = app(SmsDriverFactory::class)->make($name);

        return $this;
    }

    public function __call(string $method, array $parameters): mixed
    {
        return $this->forwardCallTo($this->driver, $method, $parameters);
    }
}

2) Adapter à plusieurs backends

Différents backends (HTTP, Queue, WebSocket, etc.) peuvent être délégués à travers une API unifiée.

3) Spy / Stub pour les tests

À la place du driver réel, injectez un Spy et faites transiter les appels via forwardCallTo tout en vérifiant le nombre d’appels et les arguments.

Pages associées

Trait Macroable

Découvrez le pattern d’extension qui ajoute de nouvelles méthodes à une classe existante.

Trait Conditionable

Apprenez à concevoir des chaînes conditionnelles avec when() / unless().
Dernière modification le 13 juillet 2026