function foobar($arg, $arg2) {
echo __FUNCTION__, " got $arg and $arg2\n";
}
foobar('one','two'); // OUTPUTS : foobar got one and two
call_user_func_array("foobar", array("one", "two")); // // OUTPUTS : foobar got one and two
Wie ich sowohl normale als auch sehen kann call_user_func_array
Methode beide Ausgänge gleich, warum sollte man sie dann bevorzugen?
In welchem Szenario wird die reguläre Aufrufmethode jedoch fehlschlagen call_user_func_array
wird nicht?
Kann ich ein solches Beispiel bekommen?
Vielen Dank
In welchem Szenario schlägt die reguläre Aufrufmethode fehl, aber call_user_func_array nicht?
Wenn Sie vorher nicht wissen, wie viele Argumente Sie an Ihre Funktion übergeben werden, wäre es ratsam, sie zu verwenden call_user_func_array()
; die einzige alternative ist a switch
Anweisung oder eine Reihe von Bedingungen, um eine vordefinierte Teilmenge von Möglichkeiten zu erreichen.
Ein anderes Szenario ist, wo die aufzurufende Funktion vorher nicht bekannt ist, z array($obj, 'method')
; hier könntest du auch gebrauchen call_user_func()
.
$fn = array($obj, 'method');
$args = [1, 2, 3];
call_user_func_array($fn, $args);
Beachten Sie, dass mit call_user_func_*
Funktionen können nicht verwendet werden, um private oder geschützte Methoden aufzurufen.
Die Alternative zu all dem besteht darin, Ihre Funktionen dazu zu bringen, ein Array als einziges Argument zu akzeptieren:
myfn([1, 2, 3]);
Dies eliminiert jedoch die Möglichkeit, jedes Argument in Ihrer Funktionsdeklaration mit einem Tipp zu versehen, und wird im Allgemeinen als Codegeruch angesehen.
Sie sollten die Funktion lieber wie gewohnt aufrufen. Verwenden call_user_func_array
mit dynamischen Argumenten. Zum Beispiel:
function func(arg1, arg2, arg3) {
return "$arg1, $arg2, $arg3";
}
func(1, 2, 3); //=> "1, 2, 3"
$args = range(5,7); // dynamic arguments
call_user_func_array('func', $args); //=> "5, 6, 7"
call_user_func_array
führt “uncurrying” durch, was das Gegenteil von “currying” ist.
Das Folgende gilt für alle “Callables” von PHP (benannte Funktionen, Closures, Methoden, __invoke
etc.), also ignorieren wir der Einfachheit halber die Unterschiede und konzentrieren uns nur auf Closures.
Wenn wir mehrere Argumente akzeptieren wollen, lässt uns PHP dies mit 3 verschiedenen APIs tun. Der übliche Weg ist dieser:
$usual = function($a, $b, $c, $d) {
return $a + $b + $c + $d;
};
$result = $usual(10, 20, 30, 40); // $result == 100
Ein anderer Weg heißt Curry bilden:
$curried = function($a) {
return function($b) use ($a) {
return function($c) use ($a, $b) {
return function($d) use ($a, $b, $c) {
return $a + $b + $c + $d;
};
};
};
};
$result = call_user_func(
call_user_func(
call_user_func(
$curried(10),
20),
30),
40); // $result == 100
Der Vorteil ist, dass alle Curry-Funktionen auf die gleiche Weise aufgerufen werden können: Geben Sie ihnen ein Argument.
Wenn mehr Argumente erforderlich sind, werden mehr Curry-Funktionen zurückgegeben, die sich an die vorherigen Argumente „erinnern“. Dies ermöglicht es uns, einige Argumente jetzt und den Rest später zu übergeben.
Dabei gibt es einige Probleme:
- Offensichtlich ist es sehr mühsam, Funktionen auf diese Weise zu schreiben und aufzurufen.
- Wenn wir Curry-Funktionen bereitstellen, werden sie umständlich sein, wenn ihre „Gedächtnis“-Fähigkeit nicht benötigt wird.
- Wenn wir uns auf die „Memory“-Fähigkeit von Curry-Funktionen verlassen, werden wir enttäuscht sein, wenn der Code anderer Leute sie nicht bereitstellt.
Wir können all diese Probleme beheben, indem wir a verwenden Konvertierungsfunktion (Haftungsausschluss: Das ist mein Blog). Dadurch können wir unsere Funktionen auf die übliche Weise schreiben und aufrufen, geben ihnen jedoch die gleiche “Speicherfähigkeit”, als wären sie Curry:
$curried = curry(function($a, $b, $c, $d) {
return $a + $b + $c + $d;
});
$result1 = $curried(10, 20, 30, 40); // $result1 = 100
$result2 = call_user_func($curried(10, 20), 30, 40); // $result2 = 100
Der dritte Weg heißt uncurry und nimmt alle seine Argumente in einem zusammen:
$uncurried = function($args) {
return $args[0] + $args[1] + $args[2] + $args[3];
};
$result = $uncurried([10, 20, 30, 40]); // $result == 100
Genau wie bei Curry-Funktionen können alle Funktionen ohne Curry mit einem Argument aufgerufen werden, obwohl es diesmal ein Array ist. Wir haben immer noch die gleichen Kompatibilitätsprobleme wie Curry-Funktionen: Wenn wir uns dafür entscheiden, nicht-Curry-Funktionen zu verwenden, können wir uns nicht darauf verlassen, dass alle anderen dasselbe wählen. Daher benötigen wir auch eine Umrechnungsfunktion für das Uncurrying. Das ist, was call_user_func_array
tut:
$uncurried = function($args) use ($usual) {
return call_user_func_array($usual, $args);
};
$result1 = $usual(10, 20, 30, 40); // $result1 = 100
$result2 = $uncurried([10, 20, 30, 40]); // $result2 = 100
Interessanterweise können wir dieses Extra loswerden function($args)
Wrapper (ein Prozess, der als “Eta-Reduktion” bekannt ist) durch Currying call_user_func_array
:
$uncurried = curry('call_user_func_array', $usual);
$result = $uncurried([10, 20, 30, 40]); // $result == 100
Leider call_user_func_array
ist nicht so schlau wie curry
; es wird nicht automatisch zwischen den beiden konvertiert. Wir können unsere eigenen schreiben uncurry
Funktion, die diese Fähigkeit hat:
function uncurry($f)
{
return function($args) use ($f) {
return call_user_func_array(
$f,
(count(func_get_args()) > 1)? func_get_args()
: $args);
};
}
$uncurried = uncurry($usual);
$result1 = $uncurried(10, 20, 30, 40); // $result1 == 100
$result2 = $uncurried([10, 20, 30, 40]); // $result2 == 100
Diese Konvertierungsfunktionen zeigen, dass die „übliche“ Art von PHP, Funktionen zu definieren, tatsächlich überflüssig ist: Wenn wir die „üblichen“ Funktionen von PHP durch „intelligente“ Curry- oder Uncurry-Funktionen ersetzen würden, würde eine Menge Code weiterarbeiten. Wenn wir das getan haben, ist es besser, alles zu curryen und nach Bedarf selektiv zu entfernen, da dies einfacher ist als umgekehrt.
Leider einige Dinge, die eine variable Anzahl von Argumenten verwenden func_get_args
würde brechen, sowie Funktionen mit Standardargumentwerten.
Interessanterweise sind Standardwerte nur eine spezielle Form des Currys. Wir könnten meistens darauf verzichten, wenn wir diese Argumente vorbringen Erste statt zuletzt und stellte eine Reihe alternativer Definitionen bereit, die in den Standardeinstellungen enthalten sind. Zum Beispiel:
$defaults = function($a, $b, $c = 30, $d = 40) {
return $a + $b + $c + $d;
};
$def1 = $defaults(10, 20, 30, 40); // $def1 == 100
$def2 = $defaults(10, 20, 30); // $def2 == 100
$def3 = $defaults(10, 20); // $def3 == 100
$curried = function($d, $c, $a, $b) {
return $a + $b + $c + $d;
};
$curriedD = $curried(40);
$curriedDC = $curriedD(30);
$cur1 = $curried(10, 20, 30, 40); // $cur1 == 100
$cur2 = $curriedD(10, 20, 30); // $cur2 == 100
$cur3 = $curriedDC(10, 20); // $cur3 == 100
Ab PHP 5.6, um eine zu übergeben Reihe statt ein Argumentliste zu einer Funktion stellen Sie dem Array einfach ein Auslassungszeichen voran (dies wird als “Argument-Entpacken” bezeichnet).
function foo($var1, $var2, $var3) {
echo $var1 + $var2 + var3;
}
$array = [1,2,3];
foo(...$array); // 6
// same as call_user_func_array('foo',$array);
Der Unterschied zwischen call_user_func_array()
und variable Funktionen Ab PHP 5.6 erlauben Variablenfunktionen nicht den Aufruf einer statischen Methode:
$params = [1,2,3,4,5];
function test_function() {
echo implode('+',func_get_args()) .'='. array_sum(func_get_args())."\r\n";
}
// Normal function as callback
$callback_function = 'test_function';
call_user_func_array($callback_function,$params); // 1+2+3+4+5=15
$callback_function(...$params); // 1+2+3+4+5=15
class TestClass
{
static function testStaticMethod() {
echo implode('+',func_get_args()) .'='. array_sum(func_get_args())."\r\n";
}
public function testMethod() {
echo implode('+',func_get_args()) .'='. array_sum(func_get_args())."\r\n";
}
}
// Class method as callback
$obj = new TestClass;
$callback_function = [$obj,'testMethod'];
call_user_func_array($callback_function,$params); // 1+2+3+4+5=15
$callback_function(...$params); // 1+2+3+4+5=15
// Static method callback
$callback_function = 'TestClass::testStaticMethod';
call_user_func_array($callback_function,$params); // 1+2+3+4+5=15
$callback_function(...$params); // Fatal error: undefined function
PHP 7 fügt die Möglichkeit hinzu, statische Methoden über eine Variablenfunktion aufzurufen, also ab PHP 7 Dies Unterschied besteht nicht mehr. Abschließend, call_user_func_array()
gibt Ihrem Code mehr Kompatibilität.
call_user_func_array
wird hauptsächlich in dynamischen Kontexten verwendet, wenn Sie nicht wissen, welche Funktion Sie aufrufen und welche Argumente Sie vorher übergeben werden.– Strickl
30. August 2013 um 6:07 Uhr
Können wir nicht die reguläre Methode für ein Array von Argumenten verwenden? @elclans
– Prinz Singh
30. August 2013 um 6:09 Uhr