2009-10-08 24 views
9

Mi situación se describe mejor con un poco de código:de PHP en subclases

class Foo { 
    function bar() { 
     echo "called Foo::bar()"; 
    } 
} 

class SubFoo extends Foo { 
    function __call($func) { 
     if ($func == "bar") { 
      echo "intercepted bar()!"; 
     } 
    } 
} 

$subFoo = new SubFoo(); 

// what actually happens: 
$subFoo->bar(); // "called Foo:bar()" 

// what would be nice: 
$subFoo->bar(); // "intercepted bar()!" 

Sé que puedo conseguir que esto funcione mediante la redefinición de bar() (y todos los otros métodos pertinentes) en el sub- clase, pero para mis propósitos, sería bueno si la función __call pudiera manejarlos. Simplemente haría las cosas más fáciles de manejar y más manejables.

¿Es esto posible en PHP?

Respuesta

13

__call() solo se invoca cuando la función no se encuentra de modo que su ejemplo, tal como está escrito, no es posible.

2

No se puede hacer directamente, pero esta es una alternativa posible:

class SubFoo { // does not extend 
    function __construct() { 
     $this->__foo = new Foo; // sub-object instead 
    } 
    function __call($func, $args) { 
     echo "intercepted $func()!\n"; 
     call_user_func_array(array($this->__foo, $func), $args); 
    } 
} 

Este tipo de cosas es bueno para la depuración y pruebas, pero se quiere evitar __call() y amigos tanto como sea posible en código de producción ya que no son muy eficientes.

+0

Esto. Debes seguir el patrón de Fachada. Tenga una clase contenedora que "posea" el objeto que desea anular todas estas funciones. Use __call() para pasar los métodos según sea necesario, haciendo cualquier trabajo adicional según corresponda. No te preocupes por el rendimiento a menos que tu código se llame constantemente y tu aplicación tenga un límite de CPU (casi nunca es el caso): el tiempo del programador es casi siempre más importante que el rendimiento para decidir sobre este tipo de intercambio. –

0

Si necesita agregar algo extra a la barra padre(), ¿sería factible?

class SubFoo extends Foo { 
    function bar() { 
     // Do something else first 
     parent::bar(); 
    } 
} 

o es solo una pregunta de la curiosidad?

+1

el problema surge del hecho de que la clase padre podría tener un montón de funciones, y no quiero tener que duplicarlas todas en la subclase, solo para aplicar el mismo comportamiento (el '// hacer algo más primero 'parte) a todos ellos – nickf

+0

@nickf Absolutamente, esto me parece algo tan necesario que no entiendo por qué no está en PHP. –

0

Lo que podría hacer para tener el mismo efecto es el siguiente:

<?php 

class hooked{ 

    public $value; 

    function __construct(){ 
     $this->value = "your function"; 
    } 

    // Only called when function does not exist. 
    function __call($name, $arguments){ 

     $reroute = array(
      "rerouted" => "hooked_function" 
     ); 

     // Set the prefix to whatever you like available in function names. 
     $prefix = "_"; 

     // Remove the prefix and check wether the function exists. 
     $function_name = substr($name, strlen($prefix)); 

     if(method_exists($this, $function_name)){ 

      // Handle prefix methods. 
      call_user_func_array(array($this, $function_name), $arguments); 

     }elseif(array_key_exists($name, $reroute)){ 

      if(method_exists($this, $reroute[$name])){ 

       call_user_func_array(array($this, $reroute[$name]), $arguments); 

      }else{ 
       throw new Exception("Function <strong>{$reroute[$name]}</strong> does not exist.\n"); 
      } 

     }else{ 
      throw new Exception("Function <strong>$name</strong> does not exist.\n"); 
     } 

    } 

    function hooked_function($one = "", $two = ""){ 

     echo "{$this->value} $one $two"; 

    } 

} 

$hooked = new hooked(); 

$hooked->_hooked_function("is", "hooked. "); 
// Echo's: "your function is hooked." 
$hooked->rerouted("is", "rerouted."); 
// Echo's: "our function is rerouted." 

?> 
1

Una cosa que puedes intentar es configurar el alcance de las funciones privada o protegida. Cuando se llama a una función privada desde fuera de la clase, llama al método mágico __call y puede explotarlo.