Callables

Ein Callable ist eine Referenz auf eine Funktion oder Methode, die einer anderen Funktion als Argument übergeben wird. Sie werden durch die Typdeklaration callable repräsentiert.

<?php
function foo(callable $callback) {
$callback();
}
?>

Einige Funktionen akzeptieren Callback-Funktionen als Parameter, zum Beispiel array_map(), usort() oder preg_replace_callback().

Erstellung von Callables

Ein Callable ist ein Typ, der etwas repräsentiert, das aufgerufen werden kann. Callables können als Argumente an Funktionen oder Methoden übergeben werden, die einen Callback-Parameter erwarten, oder sie können direkt aufgerufen werden. Der Typ callable kann nicht als Typdeklaration für Klasseneigenschaften verwendet werden. Verwenden Sie stattdessen eine Closure-Typdeklaration.

Callables können auf verschiedene Arten erstellt werden:

  • Closure-Objekt
  • Ein String, der den Namen einer Funktion oder Methode enthält
  • Ein Array, das einen Klassennamen oder ein Object an Index 0 und den Methodennamen an Index 1 enthält
  • Ein Objekt, das die magische Methode __invoke() implementiert

Ein Closure-Objekt kann mit der Syntax für anonyme Funktionen, der Syntax für Pfeilfunktionen, der Syntax für Callbacks als Objekte erster Klasse oder mit der Methode Closure::fromCallable() erstellt werden.

Hinweis: Die Syntax für Callbacks als Objekte erster Klasse ist erst ab PHP 8.1.0 verfügbar.

Beispiel #1 Callback-Beispiel mit einem Closure

<?php
// Verwendung der Syntax für anonyme Funktionen
$double1 = function ($a) {
return
$a * 2;
};

// Verwendung der Syntax für Callbacks als Objekte erster Klasse
function double_function($a) {
return
$a * 2;
}
$double2 = double_function(...);

// Verwendung der Syntax für Pfeilfunktionen
$double3 = fn($a) => $a * 2;

// Verwendung von Closure::fromCallable
$double4 = Closure::fromCallable('double_function');

// Hier wird das Closure als Callback verwendet, um
// die Größe jedes Elements unseres Bereichs zu verdoppeln
$new_numbers = array_map($double1, range(1, 5));
print
implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double2, range(1, 5));
print
implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double3, range(1, 5));
print
implode(' ', $new_numbers) . PHP_EOL;

$new_numbers = array_map($double4, range(1, 5));
print
implode(' ', $new_numbers);

?>

Das oben gezeigte Beispiel erzeugt mit PHP 8.1 folgende Ausgabe:

2 4 6 8 10
2 4 6 8 10
2 4 6 8 10
2 4 6 8 10

Ein Callable kann auch ein String sein, der den Namen einer Funktion oder einer statischen Methode enthält. Jede eingebaute oder benutzerdefinierte Funktion kann verwendet werden, außer Sprachkonstrukten wie: array(), echo, empty(), eval(), isset(), list(), print oder unset().

Statische Klassenmethoden können verwendet werden, ohne dass ein Object dieser Klasse instantiiert werden muss, indem entweder ein Array mit dem Klassennamen an Index 0 und dem Methodennamen an Index 1 erstellt wird, oder indem die spezielle Syntax mit dem Bereichsauflösungsoperator :: wie in 'ClassName::methodName' verwendet wird.

Eine Methode eines instantiierten Objects kann ein Callable sein, wenn sie als Array mit dem Object an Index 0 und dem Methodennamen an Index 1 angegeben wird.

Der Hauptunterschied zwischen einem Closure-Objekt und dem Typ callable besteht darin, dass ein Closure-Objekt unabhängig vom Geltungsbereich ist und immer aufgerufen werden kann, während ein Callable-Typ vom Geltungsbereich abhängig sein kann und möglicherweise nicht direkt aufgerufen werden kann. Closure ist die bevorzugte Art, Callables zu erstellen.

Hinweis: Während Closure-Objekte an den Geltungsbereich gebunden sind, in dem sie erstellt werden, werden Callables, die Klassenmethoden als Strings oder Arrays referenzieren, in dem Geltungsbereich aufgelöst, in dem sie aufgerufen werden. Um aus einer privaten oder geschützten Methode ein Callable zu erstellen, das dann von außerhalb des Geltungsbereichs der Klasse aufgerufen werden kann, verwenden Sie Closure::fromCallable() oder die Syntax für Callbacks als Objekte erster Klasse.

PHP erlaubt die Erstellung von Callables, die als Callback-Argument verwendet, aber nicht direkt aufgerufen werden können. Dabei handelt es sich um kontextabhängige Callables, die eine Klassenmethode in der Vererbungshierarchie einer Klasse referenzieren, zum Beispiel 'parent::method' oder ["static", "method"].

Hinweis: Seit PHP 8.2.0 sind kontextabhängige Callables veraltet. Entfernen Sie die Kontextabhängigkeit, indem Sie 'parent::method' durch parent::class . '::method' ersetzen, oder verwenden Sie die Syntax für Callbacks als Objekte erster Klasse.

Beispiel #2 Verschiedene Arten von Callables mit call_user_function() aufrufen

<?php

// Eine Beispiel-Callback-Funktion
function my_callback_function() {
echo
'hello world!', PHP_EOL;
}

// Eine Beispiel-Callback-Methode
class MyClass {
static function
myCallbackMethod() {
echo
'Hello World!', PHP_EOL;
}
}

// Typ 1: Einfaches Callback
call_user_func('my_callback_function');

// Typ 2: Statischer Methodenaufruf
call_user_func(['MyClass', 'myCallbackMethod']);

// Typ 3: Aufruf einer Objektmethode
$obj = new MyClass();
call_user_func([$obj, 'myCallbackMethod']);

// Typ 4: Statischer Methodenaufruf
call_user_func('MyClass::myCallbackMethod');

// Typ 5: Statischer Methodenaufruf mit dem Schlüsselwort ::class
call_user_func([MyClass::class, 'myCallbackMethod']);

// Typ 6: Relativer statischer Methodenaufruf
class A {
public static function
who() {
echo
'A', PHP_EOL;
}
}

class
B extends A {
public static function
who() {
echo
'B', PHP_EOL;
}
}

call_user_func(['B', 'parent::who']); // seit PHP 8.2.0 veraltet

// Typ 7: Objekte die __invoke implementieren können als Callable verwendet werden
class C {
public function
__invoke($name) {
echo
'Hello ', $name;
}
}

$c = new C();
call_user_func($c, 'PHP!');
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

hello world!
Hello World!
Hello World!
Hello World!
Hello World!

Deprecated: Callables of the form ["B", "parent::who"] are deprecated in script on line 41
A
Hello PHP!

Hinweis:

Callbacks, die für Funktionen wie call_user_func() und call_user_func_array() registriert sind, werden nicht mehr ausgeführt, wenn in einem vorherigen Callback eine Exception geworfen und nicht gefangen wurde.