Testen für eine PHP-Closure ohne Bezug auf die interne Closure-Klasse

8

Im PHP-Handbuch für anonyme Funktionen (dh Closures) heißt es:

  

Anonyme Funktionen werden derzeit mit der Closure-Klasse implementiert. Dies ist ein Implementierungsdetail und auf sollte nicht Verlass sein .

(Schwerpunkt ist mein eigener)

Ist es möglich, eine Variable so zu testen, dass der Test nur dann true zurückgibt, wenn die Variable eine Closure ist, ohne auf die Closure-Klasse zu verweisen?

Mit anderen Worten, wie kann ich Folgendes so umschreiben, dass es zu einem Fehler kommt, wenn $bar alles andere als eine anonyme Funktion ist:

%Vor%

BEARBEITEN: Basierend auf den Antworten erhalten Sie hier einen Beispieltest.

Anmerkungen:

  1. Es scheint, dass es keine Möglichkeit gibt, zwischen Fancers und Closures zu unterscheiden Der Test ist wahrscheinlich genauso "implementierungsspezifisch" wie die Verwendung der Closure-Klasse.
  2. Die (scheinbar offensichtliche) Methode ReflectionFunction::isClosure() scheint fast nutzlos zu sein: Zu der Zeit, als Sie die erforderlichen Überprüfungen durchgeführt haben, um sicherzustellen, dass ReflectionFunction tatsächlich instanziiert werden kann (außer einer Closure keine Klasse) , Sie haben alle anderen Optionen eliminiert.
  3. In 5.3.0 haben Sie ReflectionClass ($ closure) - & gt; hasMethod ('__ invoke') false zurückgegeben, also könnte dies als Test gegen Functors verwendet werden, aber (mir wurde gesagt) hat sich seitdem geändert. Dies unterstreicht die Schwachstelle der Lösung.
  4. Follow-up von Gordon - Ab PHP 5.4 können Sie sich darauf verlassen, dass Closure eine Closure ist: php.net/manual/en/class.closure.php

Code:

%Vor%

Testfall:

%Vor%

-

    
Hamish 08.11.2010, 20:52
quelle

2 Antworten

8

Sie können auch

verwenden

ReflectionFunctionAbstract::isClosure - Prüft, ob es geschlossen wurde

Beispiel:

%Vor%

Beachten Sie, dass das obige nur TRUE für PHP 5.3 Lambdas und Closures zurückgibt. Wenn Sie nur wissen möchten, ob ein Argument als Callback verwendet werden kann, wird is_callable besser funktionieren.

BEARBEITEN Wenn Sie auch Funktoren hinzufügen möchten, können Sie ( ab PHP 5.3.3 )

%Vor%

oder

%Vor%

wobei letzteres die schnellere Alternative ist.

Eine Closure -Instanz ist im Grunde genommen nur eine Klasse, die eine __invoke -Funktion hat, die Sie dem Methodenkörper im laufenden Betrieb zugeführt haben. Aber da dies ein Implementierungsdetail testet, würde ich sagen, es ist so unzuverlässig wie das Testen des Closure -Klassennamens.

BEARBEITEN Da Sie erwähnen, dass Sie nicht zuverlässig über die Reflection-API testen können, weil beim Übergeben eines Functors an ReflectionFunctionAbstract::isClosure ein Fehler auftritt, versuchen Sie, die folgende Lösung Ihren Anforderungen anzupassen:

%Vor%

Dies überprüft, ob das übergebene Argument aufrufbar ist. Das $name Argument speichert den aufrufbaren Namen. Für Schließungen ist dies zur Zeit Closure::__invoke . Da dies für alle Closures / Lambdas dasselbe sein wird, können wir den Namen des übergebenen Arguments mit einem beliebigen anderen Closure / Lambda vergleichen. Wenn sie gleich sind, muss das Argument ein Closure / Lambda sein. Das Ermitteln des aufrufbaren Namens zur Laufzeit hat den zusätzlichen Vorteil, dass Sie keine Annahmen über die Implementierungsdetails in Ihren Quellcode fest codieren müssen. Wenn Sie einen Funktor übergeben, wird FALSE zurückgegeben, da er nicht denselben aufrufbaren Namen hat. Da dies nicht auf der Reflection-API beruht, ist es wahrscheinlich auch etwas schneller.

Das obige könnte eleganter als

geschrieben werden %Vor%     
Gordon 08.11.2010, 20:59
quelle
1

is_callable und !is_array könnten Ihnen dabei helfen. Beachten Sie, dass Sie sich nicht darauf verlassen können, dass der Typhinweis von PHP auf diese Weise angezeigt wird, da Sie die Variable innerhalb der Funktion überprüfen und etwas, z. ein InvalidArgumentException selbst.

    
janmoesen 08.11.2010 20:55
quelle

Tags und Links