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:
- Callable Objects: Objects can be invoked like functions
- Stateful Functions: Maintain state between invocations
- Flexible Interfaces: Can be used anywhere callables are accepted
- Cleaner Code: Encapsulates related behavior in objects
- Polymorphism: Different classes can implement their own invoke logic
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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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.
<?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:
- Callable Objects: Makes instances callable like functions
- State Maintenance: Objects can preserve state between calls
- Flexible Usage: Works anywhere callables are accepted
- Design Patterns: Enables elegant implementations of patterns like Strategy
- Functional Programming: Supports currying, composition, and other FP techniques
- Clear Intent: Signals that an object represents an action or transformation
- Polymorphism: Different classes can implement their own invocation behavior
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
List all PHP tutorials.