In PHP 8.5, which values count as a callable, and which older callable forms are deprecated?
answer
- string name, array pair, object, Closure
- strings are always fully qualified
- 'Class::method' and [Class::class, 'method']
- 8.2: self, parent, static in callables
- the form $callable() cannot call
basics
~20 sA PHP callable is a function-name string, a 'Class::method' string, an [object or class, 'method'] array, a Closure, or an invokable object. Since PHP 8.2, relative forms such as 'self::method' or ['parent', 'method'] are deprecated.
solid answer
~40 sPHP accepts five shapes wherever a `callable` is expected: a **string** naming a function (`'strtoupper'`) or a static method (`'Slugger::clean'`); an **array** of an object or class name plus a method name (`[$slugger, 'slug']`, `[Slugger::class, 'clean']`); a **`Closure`**, whether from `function`, `fn` or the `strlen(...)` syntax; and an **object with `__invoke()`**. All of them can be invoked directly as `$callable($arg)`. String names are resolved as fully qualified, so inside a namespace `'shout'` means the global `\shout`, not `App\Text\shout`. PHP 8.2 deprecated the **relative callables** that only `call_user_func()`-style calls understood: `'self::m'`, `'parent::m'`, `'static::m'`, `['self', 'm']` and the like, and `['B', 'A::m']`. They still run in 8.5 but emit `E_DEPRECATED`; use `self::class`, `static::class` or `self::m(...)` instead.
code
php · 29 lines<?php
declare(strict_types=1);
namespace App\Text;
final class Slugger
{
public function slug(string $s): string { return strtolower(trim($s)); }
public static function clean(string $s): string { return trim($s); }
}
function shout(string $s): string { return strtoupper($s); }
$slugger = new Slugger();
$forms = [
'strtoupper', // global function
'App\Text\shout', // namespaced function: fully qualified
'App\Text\Slugger::clean', // "Class::method" string
[$slugger, 'slug'], // object + method
[Slugger::class, 'clean'], // class + static method
fn (string $s): string => $s, // Closure
shout(...), // first-class callable (8.1+)
];
foreach ($forms as $callable) {
echo '[', $callable(' Title '), ']';
}
// [ TITLE ][ TITLE ][Title][title][Title][ Title ][ TITLE ]
// 'shout' alone would mean \shout(): Error: Call to undefined function shout()go deeper
Recall the shapes a callable can take: function-name string, [object, 'method'] array, Closure and invokable object, and that each can be called as $f().
Explain namespace resolution of string callables, scope and visibility for array callables, and exactly which relative forms 8.2 deprecated.
Plan the migration of relative callables and string callbacks to first-class callables, and explain why Closure is the type to store callbacks in properties.
Decide where a codebase still accepts string or array callables, such as configuration, versus closures everywhere else, weighing flexibility against static analysis.
## What "callable" means in PHP A **callable** is any value PHP can invoke as a function. Functions such as `array_map()`, `usort()` and `preg_replace_callback()` take one, the `callable` type declaration accepts one, and `is_callable()` tests for one. PHP does not have a single function type; instead it recognises several shapes of value. ## The five forms | Form | Example | Invokes | |---|---|---| | function-name string | `'strtoupper'`, `'App\Text\shout'` | a global or namespaced function | | `"Class::method"` string | `'App\Text\Slugger::clean'` | a static method | | array `[object, 'method']` | `[$slugger, 'slug']` | an instance method on that object | | array `[class, 'method']` | `[Slugger::class, 'clean']` | a static method | | `Closure` object | `fn (string $s) => trim($s)`, `trim(...)` | the closure | | invokable object | `new TitleNormalizer()` | its `__invoke()` method | Every form can be called directly: `$callable(' Title ')`, including strings with `::` and both array forms. Language constructs such as `echo`, `isset`, `empty` or `unset` are not functions, so their names are not callables; wrap them in a function when you need one. ## Namespaces and string callables A string callable is resolved at call time with **no namespace context**. Inside `namespace App\Text;`, the call `shout($s)` finds `App\Text\shout()`, but the string `'shout'` only finds a global `\shout()`, so `array_map('shout', $titles)` throws `Error: Call to undefined function shout()`. Write the fully qualified name, `'App\Text\shout'` or `__NAMESPACE__ . '\shout'`, or avoid the string entirely with `shout(...)`, which the compiler resolves like a normal call. ## Visibility is checked where the call happens String and array callables carry no scope. `[$this, 'privateMethod']` works inside the class, but if the array is returned and invoked from outside, PHP throws `Error: Call to private method ... from global scope`. A closure created inside the class, for example `$this->privateMethod(...)`, keeps the scope it was created in and works anywhere. ## Relative callables: deprecated since PHP 8.2 Some callables only ever worked through the callback machinery (`call_user_func()`, `array_map()`, `is_callable()`, the `callable` type) and never through `$callable()`. PHP 8.2 deprecated them: - strings `"self::method"`, `"parent::method"`, `"static::method"`; - arrays `["self", "method"]`, `["parent", "method"]`, `["static", "method"]`; - arrays whose method part names another class: `["Foo", "Bar::method"]`, `[new Foo, "Bar::method"]`. In PHP 8.5 they still work but raise `Deprecated: Use of "self" in callables is deprecated` or `Deprecated: Callables of the form ["B", "A::foo"] are deprecated`. Even `is_callable()` raises the notice while returning `true`. Ordinary forms such as `"A::method"` and `["A", "method"]` are **not** affected. Replacements: 1. `[self::class, 'method']` or `[static::class, 'method']` for static methods, choosing `static::class` when late static binding is intended; 2. `[$this, 'method']` for instance methods; 3. best, a first-class callable such as `self::method(...)`, `static::method(...)` or `$this->method(...)`, which is checked when it is created and understood by static analysers. ## The `callable` type and its limits The `callable` type declaration can be used for parameters and return values but **not for properties**, because whether a string or array is callable depends on the scope it is used from. To store a callback in a property, type it `Closure` and convert on the way in (`$this->step = $step(...)` for a callable held in a variable). ## Choosing a form in modern code - Prefer **closures**: `fn` for inline logic, `name(...)` for existing functions and methods. - Keep **string and array callables** for configuration data and for code that must stay compatible with them, and write strings fully qualified. - Replace every relative callable before the deprecation turns into removal. ## Traps interviewers like to probe - **Existence is checked late.** A string or array callable is only a value; a typo surfaces when something finally calls it, often deep inside a library. - **Static methods through an instance.** `[$slugger, 'clean']` also works for a static method, but it hides the fact that no instance is needed; `[Slugger::class, 'clean']` states it. - **`is_callable()` depends on where you ask.** The same array can be callable inside a class and not outside it. - **Invokable objects are callables, not closures.** They pass a `callable` check but fail a `Closure` type declaration until converted with `$obj(...)`.
- In PHP 8.5, what should replace the deprecated callable 'static::create' inside a class?Either `[static::class, 'create']`, which keeps late static binding by resolving the class name first, or the first-class callable `static::create(...)`, which produces a `Closure` checked at creation time. Both avoid the `Use of "static" in callables is deprecated` notice. `[self::class, 'create']` is only equivalent if late static binding was not intended.
- Why does is_callable([$this, 'helper']) return true inside a class but the same array fail when a caller outside invokes it?Array and string callables carry no scope; visibility is checked wherever the check or call happens. Inside the class a private `helper()` is accessible, so `is_callable()` is true there. Invoked from outside, the same array throws `Error: Call to private method`. Returning `$this->helper(...)` instead gives the caller a closure that keeps the class scope.
saying these in an interview costs you the question
- Inside a namespace, the string 'helper' resolves to the current namespace's helper().
- 'self::method' is the recommended way to pass a static method as a callback.
- Array callables like [$obj, 'method'] cannot be called directly with $f().
- Relative callables stopped working in PHP 8.2.
- A property can be typed callable to store any callback.