2011-11-27 15 views
9

Sto lavorando con funzioni anonime in cui sto creando una funzione anonima al di fuori dell'oggetto, e quindi aggiungendolo a un oggetto successivo in cui verrà utilizzato con la magia __callStatic funzione. Le chiusure che vengono aggiunte per contenere metodi della classe genitore. Mi chiedo se sarei in grado di chiamare questi metodi dalla chiusura?Funzione anonima/Chiusura e utilizzo di self :: o static ::

Proprio ora ottengo questo errore:

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

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

tiri questo errore:

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

E

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

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

gettare questo errore perché il metodo è protetto

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

+0

Vecchio php .. In 5.5.9 posso vedere 'statica ::' in funzione anonima –

risposta

3

Closures vengono chiamati così per un motivo. Loro "racchiudono" l'ambito in cui sono definiti. Non sono semplicemente blocchi di codice che possono raccogliere l'ambito dal luogo in cui sono stati incollati.

+0

ha un senso, ma allora come si potrebbe realizzare quanto sopra senza rendere il metodo pubblico? In javascript, dovresti semplicemente salvare un riferimento alla funzione in una variabile locale e chiamarlo all'interno della chiusura. Come lo fai in PHP? –

+0

Il modo in cui funziona lo scope in JavaScript e in PHP è molto diverso. A partire da come in PHP l'ambito esterno non è visibile all'interno delle funzioni, finendo su come in JavaScript è possibile modificare l'ambito in cui viene eseguita la funzione. In altre parole: PHP non è adatto per metaprogrammazione come questa. Forse potresti fare qualcosa con l'estensione Reflection, ma non ne sono sicuro. Un altro modo sarebbe probabilmente l'uso di eval, ma questo ha i suoi stessi svantaggi. – Mchl

13

È possibile raggiungere questo obiettivo utilizzando 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; 
    } 
} 

Ora, qualsiasi funzione anonima passata a EmptyObject :: addMethod() saranno disputate nel campo di applicazione della classe di EmptyObject

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


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

EmptyObject::test(); 
+1

È necessario omettere l'argomento '__CLASS__' (o impostarlo su' 'static'', ad esempio il valore predefinito) in caso di associazione statica ritardata. –

+0

Questo è fantastico! – Sean256

12

Basta memorizzare il nome del corso e passarlo alla chiusura tramite use. È possibile chiamare qualsiasi metodo statico pubblico o acquisire proprietà statiche o costanti pubbliche in questo modo. Se la chiusura viene passata in un contesto diverso, funzionerà comunque finché il valore corretto per $class è stato passato ad esso quando è stato creato. Lavora per 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(); 
Problemi correlati