forward_static_call

Calls a callable from inside a class while preserving the current late static binding class.

Signature
forward_static_call(callable $callback, mixed ...$args): mixed
  • Added in PHP 5.3.0

Parameters

ParameterTypeDescription
$callbackcallableThe function or method to call. Usually a ['parent', 'method'] or ['ClassName', 'method'] array, or a function-name string.
$argsoptionalmixedZero or more values passed on to the callback. Variadic.

Return value

mixedThe value returned by the callback, or false on error.

Errors

Throws an Error with the message "Cannot call forward_static_call() when no class scope is active" if called from outside a class method, and a TypeError if callback is not callable.

PHP tracks two class names during a static call: the class the method is defined in (self::) and the class the call was written against (static::, late static binding). A normal call_user_func(['Base', 'method']) resets the second one to Base. forward_static_call() makes a forwarding call instead, so static:: inside the target still resolves to the subclass the chain started from.

When you need it

Almost always in a static factory or builder base class that subclasses extend. If Child::create() overrides Base::create(), does some work, and then wants to hand off to the parent implementation dynamically, forward_static_call(['parent', 'create'], ...) keeps static::class equal to Child. Written as a plain parent::create() the forwarding happens automatically; you only need this function when the target is decided at runtime.

Constraints

It must be called from within a class method. Called from a plain function or the global scope it throws an Error, which is the one behavioural difference from forward_static_call_array(). The forwarding also only applies when the called class is actually an instance of the callback's class, so pointing it at an unrelated class silently behaves like an ordinary call.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Delegating from an overridden static factory to parent::create() while keeping static::class as the subclass
  • Building a fluent static query-builder base class that subclasses extend
  • Writing a trait method that dispatches to a static method chosen at runtime without losing late static binding

Frequently asked questions

What is the difference between forward_static_call and call_user_func?

forward_static_call() keeps the current late static binding class, so static:: inside the target still resolves to the subclass the call started from, while call_user_func() resets it to the class named in the callback. Everything else about the two is the same.

Why do I get "Cannot call forward_static_call() when no class scope is active"?

You called it from a plain function, a closure with no bound class, or the global scope. Move the call into a class method, or use forward_static_call_array(), which does not require a class scope.

Do I need forward_static_call for parent::method()?

No. Writing parent::method() directly is already a forwarding call. You only need this function when the callback is chosen at runtime rather than written literally.

More examples

Delegating to a parent static factory

Prints User(name,email,id). The parent method builds its output from static::class, and because the call was forwarded that is still User rather than Model. Swapping in call_user_func() would print Model(...) instead.

Example · php
<?php
class Model
{
    public static function create(string ...$fields): string
    {
        return static::class . '(' . implode(',', $fields) . ')';
    }
}

class User extends Model
{
    public static function create(string ...$fields): string
    {
        $fields[] = 'id';
        return forward_static_call(['parent', 'create'], ...$fields);
    }
}

echo User::create('name', 'email'), "\n";

It requires a class scope

Prints 'Error: Cannot call forward_static_call() when no class scope is active' followed by 'script continues'. The check happens before the callback runs, so even a harmless target like strtoupper fails outside a class.

Example · php
<?php
function outside(): void
{
    try {
        echo forward_static_call('strtoupper', 'nope'), "\n";
    } catch (Error $e) {
        echo get_class($e), ': ', $e->getMessage(), "\n";
    }
}

outside();
echo "script continues\n";

Forwarding only applies to related classes

Prints Caller then Unrelated. The called class is only forwarded when it is an instance of the callback's class; pointing the call at an unrelated class makes it behave exactly like call_user_func().

Example · php
<?php
class Tool { public static function name(): string { return static::class; } }
class Sharp extends Tool {}
class Unrelated { public static function name(): string { return static::class; } }

class Caller extends Sharp
{
    public static function related(): string { return forward_static_call(['Tool', 'name']); }
    public static function foreign(): string { return forward_static_call(['Unrelated', 'name']); }
}

echo Caller::related(), "\n";
echo Caller::foreign(), "\n";

Discussion

  • Be the first to comment on this lesson.