2011-11-27 8 views
9

Pracuję z anonimowych funkcji, gdzie tworzę funkcję anonimową na zewnątrz obiektu, a następnie dodanie go do obiektu, w którym później będą używane z __callStatic magii funkcjonować. Zamknięcia, które są dodawane, aby zawierać metody z klasy nadrzędnej. Zastanawiam się, czy będę w stanie nazwać te metody z zamknięcia?Anonymous Funkcja/Zamknięcie i korzystania siebie lub statyczne :: ::

Teraz otrzymuję ten błąd:

EmptyObject::addMethod('open', function(){ 
    if (static::_hasAdapter(get_class(), __FUNCTION__)) 
      return self::_callAdapter(get_class(), __FUNCTION__, $details); 

    echo '<p>You have mail!</p>'; 
}); 

generuje ten błąd:

Fatal error: Cannot access static:: when no class scope is active in

I

//Add the functions 
EmptyObject::addMethod('open', function(){ 
    if (EmptyObject::_hasAdapter('EmptyObject', __FUNCTION__)) 
      return EmptyObject::_callAdapter('EmptyObject', __FUNCTION__, $details); 

    echo '<p>You have mail!</p>'; 
}); 

rzut ten błąd, ponieważ metoda jest chroniony

Fatal error: Uncaught exception 'BadMethodCallException' with message 'Method '_hasAdapter' was not found in class EmptyObject'

+0

Old php .. W 5.5.9 widzę „static ::” w Anonimous funkcji –

Odpowiedz

3

Closures nazywa się tak bez powodu. "Obejmują" zakres, w którym są zdefiniowane. Nie są to po prostu bloki kodu, które mogą wykryć zakres od miejsca, w którym zostały wklejone.

+0

sens, ale w jaki sposób zrealizować powyższe metody bez publiczności? W javascript wystarczy zapisać referencję do funkcji w zmiennej lokalnej i wywołać ją w ramach zamknięcia. Jak to zrobić w PHP? –

+0

Sposób działania zakresu w JavaScript i PHP jest bardzo różny. Począwszy od tego, jak w PHP zakres zewnętrzny nie jest widoczny wewnątrz funkcji, kończąc na tym, jak w JavaScript można zmienić zakres, w którym funkcja jest wykonywana. Innymi słowy: PHP nie jest dobrze dostosowane do metaprogramowania w ten sposób. Być może mógłbyś coś zrobić z rozszerzeniem Reflection, ale nie jestem tego pewien. Innym sposobem byłoby prawdopodobnie użycie eval, ale ma to swoje wady. – Mchl

13

Można to osiągnąć za pomocą Closure::bind() (PHP> = 5.4.0)

abstract class EmptyObject 
{ 
    protected static $methods = array(); 

    final public static function __callStatic($name, $arguments) 
    { 
     return call_user_func(self::$methods[$name], $arguments); 
    } 

    final public static function addMethod($name, $fn) 
    { 
     self::$methods[$name] = Closure::bind($fn, NULL, __CLASS__); 
    } 

    final protected static function protectedMethod() 
    { 
     echo __METHOD__ . " was called" . PHP_EOL; 
    } 
} 

Teraz każdy anonimowy funkcja przekazywane EmptyObject :: addMethod() będzie działać w zakresie klasy EmptyObject

EmptyObject::addMethod("test", function() 
{ 
    self::protectedMethod(); 
}); 


// will output: 
// EmptyObject::protectedMethod was called 

EmptyObject::test(); 
+1

Powinieneś pominąć argument "__CLASS__" (lub ustawić go na "static", np. Domyślny) w przypadku późnego wiązania statycznego. –

+0

To jest niesamowite! – Sean256

12

Po prostu zapisz nazwę klasy i przekaż ją do zamknięcia przez use. Możesz wywołać dowolną publiczną metodę statyczną lub pobrać w ten sposób publiczne właściwości statyczne lub stałe. Jeśli zamknięcie jest zamaskowane w innym kontekście nadal będzie ona działać tak długo, jak prawidłowa wartość dla $class został przekazany do niego, kiedy została ona utworzona. Działa na PHP 5.3:

class test { 
    public static function callMe() { echo 'call me '; } 

    public static function runTest() { 
     $class = __CLASS__; 
     $call = function() use ($class) { 
      $class::callMe(); 
     }; 
     $call(); 
    } 
} 
test::runTest();