2015-01-20 19 views
6

Zamknięcie zdefiniowane w PHP może również zawierać modyfikator static.Ustalenie, czy zamknięcie jest statyczne w PHP

$f = function() { }; 

$g = static function() { }; 

Statyczny zamknięcie nie może być związany przez Closure::bind lub Closure::bindTo i wyśle ​​ostrzeżenie.

$g = Closure::bind(static function() { }, new stdClass()); 

// Warning: Cannot bind an instance to a static closure in ... 

to również w przypadku zamknięcia utworzonych przez odbicie statyczne metody z ReflectionMethod::getClosure.

class MyClass 
{ 
    public static function myStaticMethod() { } 
} 

// reflect MyClass::myStaticMethod, create an unbound closure, and try to bind it 
$f = (new ReflectionMethod(MyClass::class, 'myStaticMethod')) 
    ->getClosure() 
    ->bindTo(new stdClass()); 

// Warning: Cannot bind an instance to a static closure in ... 

Podczas denerwowania jest to dopuszczalne; jak jednak przeprowadzić test między zamknięciem statycznym a niestatycznym?

ReflectionMethod::isStatic wydawało się, że potęga pracy, ale sensownie nie jak Closure::__invoke jest instancja poziomu, a nie statyczne.

$f = static function() { }; 

// reflect Closure::__invoke because I think I'm tricky 
$r = new ReflectionMethod($f, '__invoke'); 

// and it's not static anyway 
var_dump($r->isStatic()); // bool(false) 

Ponadto sprawdzanie ReflectionMethod::getClosureThis mogą ogólnie działać jako metody statycznej musi być ograniczeń, tym niemniej nie pokrywa zamknięcia poza określone metodą przykład, względnie narożny przypadku metod np które zostały niezwiązanego .

class MyClass 
{ 
    public function myInstanceMethod() { } 
} 

$o = new MyClass(); 

// reflect MyClass::myInstanceMethod, create a bound closure, and then unbind it 
$f = (new ReflectionMethod($o, 'myInstanceMethod')) 
    ->getClosure($o) 
    ->bindTo(null); 

// then reflect the closure 
$r = new ReflectionFunction($f); 

// and see it's bound to nothing, as would be the case of a static closure 
var_dump($r->getClosureThis()); // NULL 

Tak, przekształcania, jaki sposób określić, czy zamknięcie jest statyczna (lub bardziej konkretnie, Bindable), czy nie?

Naprawdę wydaje się, że powinniśmy mieć ReflectionFunctionAbstract::isBindable lub ReflectionMethod::isStatic zostać przeniesiony do ReflectionFunctionAbstract.

Odpowiedz

5

Jeśli wiążące prace, zamknięcie będzie miał $ to wiąże się z nim. Tak więc, po prostu zwiąż to, a następnie sprawdź $ this. Jeśli jest pusty, to jest to statyczne Zamknięcie.

function isBindable(\Closure $closure) { 
    return (new ReflectionFunction(@\Closure::bind($closure, new stdClass)))->getClosureThis() != null; 
} 
+0

Ten fragment wygląda wyjątkowo znajomo ;-) – Dan

+0

To jedyny sposób, jaki widziałem do tej pory. –

+0

Podobnie. Nie podoba mi się to, że jest brudna z powodu '@ ', ale działa niezawodnie, i nie ma żadnych skrzynek narożnych, które mogę znaleźć. – Dan

2

Teraz wydaje się niemożliwe.
Tutaj można znaleźć kilka debat: https://bugs.php.net/bug.php?id=64761
Jedynym rozwiązaniem, z którego korzystam obecnie, jest ręczne dodanie właściwości ->isBindable.

Oto niektóre kodu znalazłem tutaj https://github.com/atoum/atoum/blob/master/classes/test/adapter/invoker.php
Może da ci kilka pomysłów

protected static function isBindable(\closure $closure) 
    { 
     $isBindable = (version_compare(PHP_VERSION, '5.4.0') >= 0); 
     if ($isBindable === true) 
     { 
      $reflectedClosure = new \reflectionFunction($closure); 
      $isBindable = ($reflectedClosure->getClosureThis() !== null || $reflectedClosure->getClosureScopeClass() === null); 
     } 
     return $isBindable; 
    } 
+0

To nie poradzi sobie z przypadkiem, w którym jest wiążące, ale nie wiąże się z niczym, ani nie ma klasy zasięgu. – bwoebi

Powiązane problemy