2011-11-27 12 views
9

Estoy trabajando con funciones anónimas donde estoy creando una función anónima fuera del objeto, y luego la agrego a un objeto más tarde en el que se usará con magia __callStatic función. Los cierres que se agregan contienen métodos de la clase principal. Me pregunto si podría llamar a esos métodos desde el cierre.Anónimo Función/Cierre y uso de uno mismo :: o estático ::

En este momento me sale este error:

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

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

tiros este error:

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

Y

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

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

tiro este error porque el método está protegido

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

+0

Antiguo php .. En 5.5.9 puedo ver 'estática ::' en función anónima –

Respuesta

3

Closures se llaman así por una razón. Ellos 'encierran' el alcance en el que están definidos. No son simplemente bloques de código que pueden recoger el alcance desde el lugar donde están pegados.

+0

tiene sentido, pero entonces ¿cómo lograr lo anterior sin que el público método? En javascript, simplemente guardará una referencia a la función en una variable local y la llamará dentro del cierre. ¿Cómo se hace esto en PHP? –

+0

La forma en que scope funciona en JavaScript y PHP es muy diferente. A partir de cómo en PHP el alcance externo no es visible dentro de las funciones, terminando en cómo en JavaScript puede cambiar el alcance en el que se ejecuta la función. En otras palabras: PHP no es muy adecuado para metaprogramar de esta manera. Tal vez podrías hacer algo con la extensión Reflection, pero no estoy seguro de eso. Otra forma sería usar eval probablemente, pero eso tiene sus propios inconvenientes. – Mchl

13

Esto se puede conseguir mediante el uso de 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; 
    } 
} 

Ahora, cualquier función anónima pasado a EmptyObject :: addMethod() se ejecutará en el ámbito de la clase EmptyObject

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


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

EmptyObject::test(); 
+1

Debe omitir el argumento '__CLASS__' (o establecerlo en' 'static'', por ejemplo, el predeterminado) en caso de enlace estático tardío. –

+0

¡Esto es asombroso! – Sean256

12

Simplemente almacene el nombre de la clase y páselo al cierre a través del use. Puede llamar a cualquier método público estático o tomar propiedades o constantes públicas estáticas de esta manera. Si el cierre se transfiere a un contexto diferente, seguirá funcionando siempre que se le haya pasado el valor correcto para $class cuando se creó. Trabaja para 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(); 
Cuestiones relacionadas