PHP está manejando incorrectamente mi llamada estática

Tengo un problema en PHP 5.3. Necesito llamar a un método usando __callStatic , pero si lo uso en un objeto instancied, PHP llama a __call en __call lugar.

Por encima de un ejemplo de la vida real:

 c}"; } static function __callStatic($method, $args){ echo 'Fine!'; } } class B extends A { public $c = 'Real Ops!'; function useCallStatic(){ static::foo(); // === A::foo(); // === B::foo(); } } $foo = new B(); $foo->useCallStatic(); // This works: // B::foo(); ?> 

Grabados : ¡Ops! No funciona Real Ops!

Tenga en cuenta que llamo useCallStatic desde un new B() . Si llamo directamente funciona bien como B::foo() .

¿Qué puedo hacer para que funcione bien?

Después de pensarlo, no es realmente un error. Pero definitivamente no es intuitivo.

 foo(); 

Esto es válido y llama a bar (). No significa barra de llamada estáticamente. Significa buscar el nombre de clase actual y la bar función de llamada bar si existe, ya sea que se trate de una función estática o no.

Para aclarar un poco más: ¿crees que parent::bar() significa llamar a una función estática llamada bar() ? No, significa que llamar a cualquier función se llama bar() .

Considerar:

 foo(); 

El método parent::nonExistant() invoca A::__call() , al igual que static::nonExistant() . Invocar A::__callStatic() para cualquiera de las llamadas sería igual de válido. No hay forma de que PHP sepa a cuál te quieres llamar. Sin embargo, por diseño, PHP le da a __call la prioridad cuando se invoca desde este tipo de contexto.

parent::regularMethod() invoca la función no estática regularMethod() . (De nuevo, el operador :: no significa “llamar a esta función estática”). Asimismo, parent::staticMethod() invoca A::staticMethod() como uno podría esperar.

Para resolver su problema:

Puede llamar manualmente a self::__callStatic('foo') en la clase heredada.

O dentro del método __call del filtro clase A contra una lista conocida y llame a self::__callStatic .

 function __call($f, $a) { if ($f == 'foo') return self::__callStatic($f, $a); else { } } 

Es feo, pero al menos las personas que extienden la clase no necesitarán hacer nada especial.

Esto es probablemente debido a la notación estándar de llamar a los métodos principales, independientemente del estado. Usted podría verificar si la palabra clave $this se establece en el método __call y si no, realice una llamada a __callStatic ?

EDITAR: Esto no es un error per se, la llamada estática se realiza desde un contexto de objeto. Eche un vistazo a este hilo de error en php .

Primero, asegúrese de estar usando PHP 5.3.0 o posterior, ya que es cuando se implementó __callStatic. Todo parece funcionar como se esperaba, ver este ejemplo:

 foo('abc'); A::bar('123'); class B extends A { function invokeStatic($args) { echo 'B::invokeStatic', PHP_EOL; self::someStatic($args); } } $b = new B; $b->invokeStatic('456'); ?> 

La salida debe ser (o al menos, es para mí):

 A::__call, array ( 0 => 'foo', 1 => array ( 0 => 'abc', ), ) A::__callStatic, array ( 0 => 'bar', 1 => array ( 0 => '123', ), ) B::invokeStatic A::__callStatic, array ( 0 => 'someStatic', 1 => array ( 0 => '456', ), ) 

Cuando ejecuto su ejemplo anterior, me sale “¡Bien!” como el único resultado, que es exactamente lo que habría esperado.

¿Exactamente qué versión de PHP estás ejecutando? Puedes verificar con esto:

 $ php -r 'echo phpversion(), PHP_EOL;' 5.3.3-7+squeeze1 

La herencia de métodos estáticos es un poco raro en PHP. Sospecho que debes redefinir __callStatic en B

Buenas noticias

Hago un gran trabajo alrededor, pero funciona bastante bien. Este es el código:

 class NoContext { public static function call($callback, $args = null){ return call_user_func_array($callback, $args ?: array()); } } 

NoContext::call llamar a NoContext::call (estáticamente) como si llamara call_user_func o similar. Eliminará el $this contexto. Todavía creo que es un error de PHP, pero …

Para resolver mi problema, lo hago:

 class B extends A { function useCallStatic(){ NoContext::call('A::foo'); } } 

Y se imprimirá: Fine! .

Gracias a todos los que me ayudan. Realmente aprendo demasiado con tus respuestas y espero que mis consejos sean útiles para ti alguna vez.