php class methods static php-5.3

PHP está manejando incorrectamente mi llamada estática



class methods (5)

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 $this palabra clave está establecida en el método __call y si no, haga 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 .

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:

<?php class A { function __call($method, $args){ // Note: $this is defined! echo "Ops! Don''t works. {$this->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?


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


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

<?php class A { public function foo() { static::bar(); } public function bar() { echo "bar()/n"; } } $a = new A(); $a->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:

<?php class A { function __call($name, $args) { echo "__call()/n"; } static function __callStatic($name, $ags) { echo "__callStatic()/n"; } function regularMethod() { echo "regularMethod()/n"; } static function staticMethod() { echo "staticMethod()/n"; } } class B extends A { function foo() { parent::nonExistant(); static::nonExistant(); parent::regularMethod(); parent::staticMethod(); } } $b = new B(); $b->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.


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:

<?php class A { public function __call($method, $args) { echo ''A::__call, '' . var_export(array($method, $args), true), PHP_EOL; } /** As of PHP 5.3.0 */ public static function __callStatic($method, $args) { echo ''A::__callStatic, '' . var_export(array($method, $args), true), PHP_EOL; } } $a = new A; $a->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


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.