ZetCode

PHP __invoke method

last modified May 28, 2025

In this article, we explore PHP's __invoke magic method, which allows objects to be called as functions. When a class implements __invoke, instances of that class become callable objects that can be invoked like functions.

The __invoke method enables objects to maintain state between calls while providing function-like behavior. This powerful feature bridges the gap between object-oriented and functional programming paradigms in PHP.

The advantages of PHP's __invoke method are:

By using __invoke, developers can create more expressive and flexible code that combines the benefits of objects and functions.

The __invoke method is defined in a class and gets called when an object is invoked as a function. It can accept any number of parameters and return any value, just like a regular function.

Simple Greeter Example

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

greeter_invoke.php
<?php

declare(strict_types=1);

class Greeter {

    public function __invoke(string $name): string {
        return "Hello, $name!";
    }
}

$greet = new Greeter();
echo $greet('John') . "\n";

// Check if object is callable
var_dump(is_callable($greet));

// Using as a callback
$names = ['Alice', 'Bob', 'Charlie'];
$greetings = array_map($greet, $names);
print_r($greetings);

This example demonstrates a simple Greeter class where instances can be called like functions to produce a greeting. It also shows the object being used as a callback with array_map.

λ php greeter_invoke.php
Hello, John!
bool(true)(
    [0] => Hello, Alice!
    [1] => Hello, Bob!
    [2] => Hello, Charlie!
)

Calculator with Multiple Parameters

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

calculator_invoke.php
<?php

declare(strict_types=1);

class Calculator {
    
    public function __invoke(float $a, float $b, string $operation): float {
        return match($operation) {
            '+' => $a + $b,
            '-' => $a - $b,
            '*' => $a * $b,
            '/' => $a / $b,
            default => throw new InvalidArgumentException("Unknown operation")
        };
    }
}

$calc = new Calculator();
echo "5 + 3 = " . $calc(5, 3, '+') . "\n";
echo "5 * 3 = " . $calc(5, 3, '*') . "\n";

The Calculator class shows how __invoke can handle multiple parameters to perform arithmetic operations.

λ php calculator_invoke.php
5 + 3 = 8
5 * 3 = 15

Unlike regular functions, objects with __invoke can maintain internal state between calls. This allows for powerful patterns like configurable functions or function-like objects that remember previous interactions.

Counter with State

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

counter_invoke.php
<?php

declare(strict_types=1);

class Counter {
    private int $count = 0;

    public function __invoke(): int {
        return ++$this->count;
    }

    public function reset(): void {
        $this->count = 0;
    }
}

$counter = new Counter();
echo $counter() . "\n";
echo $counter() . "\n";
echo $counter() . "\n";

$counter->reset();
echo $counter() . "\n";

The Counter class maintains an internal count, incrementing it with each invocation and allowing reset through a method.

λ php counter_invoke.php
1
2
3
1

Configurable Logger

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

logger_invoke.php
<?php

declare(strict_types=1);

class Logger {
    private string $prefix;

    public function __construct(string $prefix) {
        $this->prefix = $prefix;
    }

    public function __invoke(string $message): void {
        echo "[{$this->prefix}] " . date('Y-m-d H:i:s') . " - $message\n";
    }
}

$infoLogger = new Logger('INFO');
$infoLogger('Application started');

$errorLogger = new Logger('ERROR');
$errorLogger('Something went wrong!');

The Logger class is configurable via a constructor, allowing different instances to log with different prefixes.

λ php logger_invoke.php
[INFO] 2025-05-28 00:00:00 - Application started
[ERROR] 2025-05-28 00:00:00 - Something went wrong!

Caching Function Results

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

cached_function_invoke.php
<?php

declare(strict_types=1);

class CachedFunction {
    private array $cache = [];
    private $function;

    public function __construct(callable $function) {
        $this->function = $function;
    }

    public function __invoke($arg) {
        if (!array_key_exists($arg, $this->cache)) {
            $this->cache[$arg] = ($this->function)($arg);
        }
        return $this->cache[$arg];
    }
}

$expensiveFunction = function($x) {
    sleep(1); // Simulate expensive computation
    return $x * 2;
};

$cached = new CachedFunction($expensiveFunction);

echo "First call (slow): ";
$start = microtime(true);
echo $cached(5) . " - ";
echo round(microtime(true) - $start, 3) . "s\n";

echo "Second call (fast): ";
$start = microtime(true);
echo $cached(5) . " - ";
echo round(microtime(true) - $start, 3) . "s\n";

The CachedFunction class memoizes results to optimize performance of expensive computations.

λ php cached_function_invoke.php
First call (slow): 10 - 1.003s
Second call (fast): 10 - 0.000s

Practical use cases

The __invoke method has many practical applications in PHP development. Here are some common scenarios where it proves particularly useful.

Strategy Pattern Implementation

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

discount_strategy.php
<?php

declare(strict_types=1);

interface DiscountStrategy {
    public function __invoke(float $amount): float;
}

class NoDiscount implements DiscountStrategy {
    public function __invoke(float $amount): float {
        return $amount;
    }
}

class PercentageDiscount implements DiscountStrategy {
    private float $percentage;

    public function __construct(float $percentage) {
        $this->percentage = $percentage;
    }

    public function __invoke(float $amount): float {
        return $amount * (1 - $this->percentage / 100);
    }
}

class FixedDiscount implements DiscountStrategy {
    private float $discount;

    public function __construct(float $discount) {
        $this->discount = $discount;
    }

    public function __invoke(float $amount): float {
        return max(0, $amount - $this->discount);
    }
}

function applyDiscount(float $amount, DiscountStrategy $discount): float {
    return $discount($amount);
}

$orderAmount = 100;
echo "No discount: " . applyDiscount($orderAmount, new NoDiscount()) . "\n";
echo "10% discount: " . applyDiscount($orderAmount, new PercentageDiscount(10)) . "\n";
echo "$20 discount: " . applyDiscount($orderAmount, new FixedDiscount(20)) . "\n";

This example shows the strategy pattern using __invoke to apply different discount strategies polymorphically.

λ php discount_strategy.php
No discount: 100
10% discount: 90
$20 discount: 80

Middleware Pipeline

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

middleware_invoke.php
<?php

declare(strict_types=1);

class Middleware {

    private $next;
    private $action;

    public function __construct(callable $action, ?callable $next = null) {
        $this->action = $action;
        $this->next = $next;
    }

    public function __invoke($request) {
        $result = ($this->action)($request);
        return $this->next ? ($this->next)($result) : $result;
    }
}

$middleware1 = new Middleware(
    fn($x) => $x * 2,
    new Middleware(
        fn($x) => $x + 5,
        new Middleware(
            fn($x) => $x / 3
        )
    )
);

echo "Middleware result: " . $middleware1(10) . "\n";

The Middleware class demonstrates a simple middleware pipeline where each middleware can transform the request and pass it to the next one. This pattern is commonly used in web frameworks to handle requests and responses in a modular way.

λ php middleware_invoke.php
Middleware result: 8.3333333333333

Value Objects with Function Behavior

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

money_invoke.php
<?php

declare(strict_types=1);

class Money {

    private float $amount;
    private string $currency;

    public function __construct(float $amount, string $currency) {
        $this->amount = $amount;
        $this->currency = $currency;
    }

    public function __invoke(float $rate): Money {
        return new Money($this->amount * $rate, $this->currency);
    }

    public function getAmount(): float {
        return $this->amount;
    }

    public function getCurrency(): string {
        return $this->currency;
    }
}

$usd = new Money(100, 'USD');
$converted = $usd(0.85); // Convert to EUR at 0.85 rate
echo "Converted amount: " . $converted->getAmount() . " " . $converted->getCurrency() . "\n";

The Money class uses __invoke to convert amounts based on a given rate, allowing for a natural function-like syntax.

λ php money_invoke.php
Converted amount: 85 USD

Currying with __invoke

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

The __invoke method can be used to implement currying, a functional programming technique that allows functions to be partially applied. This means you can create new functions by fixing some arguments of an existing function, enabling more flexible and reusable code. This is particularly useful for creating specialized functions from more general ones, allowing for cleaner and more modular code.

curry_invoke.php
<?php

declare(strict_types=1);

class Curry {

    private $function;
    private array $args;

    public function __construct(callable $function, array $args = []) {
        $this->function = $function;
        $this->args = $args;
    }

    public function __invoke(...$args) {
        $newArgs = array_merge($this->args, $args);
        $reflection = new ReflectionFunction($this->function);
        
        if (count($newArgs) >= $reflection->getNumberOfRequiredParameters()) {
            return $reflection->invokeArgs($newArgs);
        }
        
        return new self($this->function, $newArgs);
    }
}

$add = new Curry(function($a, $b, $c) {
    return $a + $b + $c;
});

$add5 = $add(5);
$add5And10 = $add5(10);
echo "Curried result: " . $add5And10(15) . "\n"; // 30

The Curry class allows for partial application of functions. It takes a callable and accumulates arguments until enough are provided to invoke the original function. This enables creating specialized functions from more general ones, allowing for cleaner and more modular code.

λ php curry_invoke.php
Curried result: 30

Function Composition

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

The __invoke method can be used to compose multiple functions into a single callable object. This allows chaining of operations, where the output of one function becomes the input to the next. This technique is useful for creating pipelines of transformations or operations on data.

compose_invoke.php
<?php

declare(strict_types=1);

class Compose {

    private array $functions;

    public function __construct(callable ...$functions) {
        $this->functions = $functions;
    }

    public function __invoke($value) {
        return array_reduce(
            array_reverse($this->functions),
            fn($carry, $fn) => $fn($carry),
            $value
        );
    }
}

$composed = new Compose(
    fn($x) => $x * 2,
    fn($x) => $x + 3,
    fn($x) => $x / 4
);

echo "Composed result: " . $composed(10) . "\n"; // ((10/4)+3)*2 = 11

The Compose class chains multiple functions together, applying them in sequence. The output of each function becomes the input for the next, allowing for complex transformations in a clean and readable way.

λ php compose_invoke.php
Composed result: 11

Domain-Specific Language (DSL)

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

The __invoke method can be used to create a fluent interface or Domain-Specific Language (DSL) for building complex queries or configurations. This allows developers to express operations in a more natural, readable way. For example, a query builder can be implemented using __invoke to build SQL queries in a fluent style.

query_builder_invoke.php
<?php

declare(strict_types=1);

class QueryBuilder {
    private array $query = [];

    public function select(...$fields): self {
        $this->query['select'] = $fields;
        return $this;
    }

    public function where(string $field, string $operator, $value): self {
        $this->query['where'][] = [$field, $operator, $value];
        return $this;
    }

    public function __invoke(): string {
        $select = implode(', ', $this->query['select'] ?? ['*']);
        $where = '';
        
        if (!empty($this->query['where'])) {
            $conditions = array_map(
                fn($cond) => "{$cond[0]} {$cond[1]} '{$cond[2]}'",
                $this->query['where']
            );
            $where = ' WHERE ' . implode(' AND ', $conditions);
        }
        
        return "SELECT $select FROM table$where";
    }
}

$query = new QueryBuilder();
$sql = $query
    ->select('id', 'name', 'email')
    ->where('age', '>', 18)
    ->where('status', '=', 'active')
    (); // Invoke to get SQL

echo "Generated SQL: $sql\n";

The QueryBuilder creates a fluent DSL for building SQL queries. It allows chaining methods to specify fields and conditions, and the __invoke method generates the final SQL string when called.

λ php query_builder_invoke.php
Generated SQL: SELECT id, name, email FROM table WHERE age > '18' AND status = 'active'

Memoization Decorator

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

The __invoke method can also be used to create a memoization decorator that caches results of expensive function calls. This is particularly useful for recursive functions or computationally intensive operations. This technique can significantly improve performance by avoiding redundant calculations, especially in cases like the Fibonacci sequence or other recursive algorithms.

memoize_invoke.php
<?php

declare(strict_types=1);

class Memoize {
    private $function;
    private array $cache = [];

    public function __construct(callable $function) {
        $this->function = $function;
    }

    public function __invoke(...$args) {
        $key = serialize($args);
        
        if (!array_key_exists($key, $this->cache)) {
            $this->cache[$key] = ($this->function)(...$args);
        }
        
        return $this->cache[$key];
    }
}

$fibonacci = new Memoize(function($n) use (&$fibonacci) {
    return $n <= 1 ? $n : $fibonacci($n - 1) + $fibonacci($n - 2);
});

echo "Fibonacci(10): " . $fibonacci(10) . "\n";

The Memoize class optimizes recursive functions like Fibonacci by caching results.

λ php memoize_invoke.php
Fibonacci(10): 55

Best practices

Follow these best practices when working with PHP's __invoke method to ensure clean, maintainable, and effective code.

Best Practices Examples

The __invoke method is often used to create objects that behave like functions. This allows for a more natural syntax when using objects in contexts where functions are expected, such as callbacks or higher-order functions.

best_practices.php
<?php

declare(strict_types=1);

// 1. Use for single-purpose callable objects
class DiscountCalculator {
    public function __invoke(float $amount): float {
        return $amount * 0.9; // Example 10% discount
    }
}

// 2. Document behavior clearly
/**
 * Class that transforms strings according to configured rules
 * @method string __invoke(string $input) Transforms input string
 */
class StringTransformer {
    public function __invoke(string $input): string {
        return strtoupper($input);
    }
}

// 3. Consider implementing other interfaces too
interface LoggerInterface {
    public function log(string $message): void;
}

class Logger implements LoggerInterface {
    public function log(string $message): void {
        echo "LOG: $message\n";
    }
    public function __invoke(string $message): void {
        $this->log($message);
    }
}

// 4. Use type hints for parameters and return values
class Validator {
    public function __invoke(mixed $value): bool {
        return !empty($value);
    }
}

// 5. Keep __invoke focused
class OrderProcessor {
    public function __invoke(Order $order): void {
        $this->validate($order);
        $this->applyDiscounts($order);
        $this->save($order);
    }
    
    private function validate(Order $order): void { /* ... */ }
    private function applyDiscounts(Order $order): void { /* ... */ }
    private function save(Order $order): void { /* ... */ }
}

// 6. Consider alternatives for simple cases
$simpleGreet = fn($name) => "Hello, $name!";
echo $simpleGreet('Alice') . "\n";

// 7. Be consistent with invocation patterns
$logger = new Logger();
$logger('message'); // Preferred

// 8. Use for natural function-like behavior
$isPositive = new class {
    public function __invoke(float $n): bool {
        return $n > 0;
    }
};

var_dump($isPositive(5)); // true
var_dump($isPositive(-3)); // false

// 9. Use with PHP's functional programming features
$numbers = [1, -2, 3, -4, 5];
$positiveNumbers = array_filter($numbers, $isPositive);
print_r($positiveNumbers);

These practices help ensure you use __invoke effectively while avoiding common pitfalls. Key considerations include single responsibility, clear documentation, and appropriate use cases.

λ php best_practices.php
Hello, Alice!
LOG: message
bool(true)
bool(false)
Array
(
    [0] => 1
    [2] => 3
    [4] => 5
)

PHP's __invoke magic method is a powerful feature that bridges object-oriented and functional programming. Key points to remember:

The __invoke method is particularly valuable when you need objects that combine state with function-like behavior. It enables expressive code that can be both powerful and easy to understand when used appropriately.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all PHP tutorials.