2009-12-22 12 views
48

¿Cómo puedo llamar a una función de una clase secundaria de la clase principal? Considere esto:PHP: Cómo llamar a la función de una clase secundaria de la clase principal

class whale 
{ 
    function __construct() 
    { 
    // some code here 
    } 

    function myfunc() 
    { 
    // how do i call the "test" function of fish class here?? 
    } 
} 

class fish extends whale 
{ 
    function __construct() 
    { 
    parent::construct(); 
    } 

    function test() 
    { 
    echo "So you managed to call me !!"; 
    } 

} 
+0

sé que he puesto en marcha nombres de las clases equivocadas, pero esto es sólo un ejemplo, no es algo que voy a poner en práctica en cualquier lugar. – Sarfraz

+8

en una vista lógica, 'pescado' debe ser la clase principal y' ballena' el niño;; – Strae

+23

@DaNieL Una ballena no es un pez. –

Respuesta

87

Eso es lo que son para abstract classes. Una clase abstracta básicamente dice: Quien hereda de mí, debe tener esta función (o estas funciones).

abstract class whale 
{ 

    function __construct() 
    { 
    // some code here 
    } 

    function myfunc() 
    { 
    $this->test(); 
    } 

    abstract function test(); 
} 


class fish extends whale 
{ 
    function __construct() 
    { 
    parent::__construct(); 
    } 

    function test() 
    { 
    echo "So you managed to call me !!"; 
    } 

} 


$fish = new fish(); 
$fish->test(); 
$fish->myfunc(); 
+14

Aunque es correcto, creo que quiere '' whale = new Whale; $ fish = new Fish; 'y luego' $ whale-> myfunc(); 'se supone que llama a' $ fish-> test(); 'sin saber que $ fish existe. – Gordon

+0

+1, los métodos abstractos generalmente son la respuesta a su pregunta de que las clases principales se refieran a los métodos en las clases secundarias. Si Gordon está en lo cierto y realmente intentas hacer algo diferente/específico como ese, debes aclararlo. De lo contrario, esto debería ser aceptado. – philfreo

+0

También busqué esto, pero su respuesta no es lo que quiero: ballena = nueva ballena(); $ whale-> test(); :(Así que una cosa en la que estoy pensando - cuando se llama controlador de ballenas, luego simplemente redirige al controlador de peces y llama. Pero de alguna manera se siente que los redireccionamientos se están retrasando. –

0

¿qué pasa si la ballena no se extiende? ¿Cómo sería la llamada de esa función? Desafortunadamente no hay forma de hacerlo.

Oh, y un pez extiende una ballena? Un pez es un pez, una ballena es un mamífero.

+0

de todos modos, no pude entender tu respuesta, ¿puedes sugerirle una alternativa? – Sarfraz

+0

Esto no es logico. Si esa ballena no recibió clases de niños, no se extiende, por lo tanto, no hay un método para llamar desde allí. – Thielicious

8

Ok, bueno, hay tantas cosas mal con esta pregunta que realmente no sé por dónde empezar.

En primer lugar, los peces no son ballenas y las ballenas no son peces. Las ballenas son mamíferos.

En segundo lugar, si desea llamar a una función en una clase secundaria de una clase principal que no exista en su clase principal, entonces su abstracción es gravemente defectuosa y debe reconsiderarla desde cero.

En tercer lugar, en PHP que sólo podía hacer:

function myfunc() { 
    $this->test(); 
} 

En una instancia de whale que causará un error. En una instancia de fish debería funcionar.

+4

+1 for- En primer lugar, los peces no son ballenas y las ballenas no son peces. Las ballenas son mamíferos. –

1

La única manera en que podría hacer esto sería a través de reflection. Sin embargo, la reflexión es costosa y solo debe usarse cuando sea necesario.

El verdadero problema aquí es que una clase principal nunca debe confiar en la existencia de un método de clase hija. Este es un principio rector de OOD e indica que hay un defecto grave en su diseño.

Si su clase primaria es dependiente de un hijo específico, no puede usarse por ninguna otra clase secundaria que pueda extenderla también. La relación padre-hijo va de la abstracción a la especificidad, y no al revés. Sería mucho, mucho mejor que poner la función requerida en la clase principal en su lugar, y anularla en las clases secundarias si es necesario. Algo como esto:

class whale 
{ 
    function myfunc() 
    { 
     echo "I am a ".get_class($this); 
    } 
} 

class fish extends whale 
{ 
    function myfunc() 
    { 
    echo "I am always a fish."; 
    } 
} 
+0

Dudo que se pueda hacer con Reflection. La ballena debería tener Fish codificado en alguna parte. – Gordon

+0

que es una gran información :) – Sarfraz

15

Técnicamente, no se puede llamar una instancia de pescado (niño) de una instancia de ballena (padre), pero dado que se trata de la herencia, myFunc() estará disponible en la instancia de peces de todos modos, para que pueda llamar al $yourFishInstance->myFunc() directamente.

Si hace referencia al template method pattern, simplemente escriba $this->test() como cuerpo del método. Llamar al myFunc() desde una instancia de pez delegará la llamada al test() en la instancia de pez. Pero nuevamente, no hay llamadas desde una instancia de ballena a una instancia de pez.

En una nota, una ballena es un mamífero y no un pez;)

+0

esto es solo un ejemplo amigo, no voy a implementar esos nombres en ningún lado :) – Sarfraz

2

me gustaría ir con la clase abstracta ....
pero en PHP no lo hace tienen que usarlos para hacer que funcione.Incluso la invocación del constructor de la clase padre es una llamada al método "normal" y el objeto es completamente "operativo" en este punto, es decir, $ esto "sabe" sobre todos los miembros, heredados o no.

class Foo 
{ 
    public function __construct() { 
    echo "Foo::__construct()\n"; 
    $this->init(); 
    } 
} 

class Bar extends Foo 
{ 
    public function __construct() { 
    echo "Bar::__construct()\n"; 
    parent::__construct(); 
    } 

    public function init() { 
    echo "Bar::init()\n"; 
    } 
} 

$b = new Bar; 

impresiones

Bar::__construct() 
Foo::__construct() 
Bar::init() 

es decir, a pesar de que la clase Foo no sabe nada acerca de un init función() puede llamar al método ya que la búsqueda se basa en lo que esto es $ una referencia a.
Ese es el aspecto técnico. Pero realmente debe hacer cumplir la implementación de ese método ya sea haciéndolo abstracto (forzando a los descendientes a implementarlo) o proporcionando una implementación predeterminada que se puede sobrescribir.

2

Sé que es probable que sea un poco tarde para ti, pero también tuve que solucionar este problema. Para ayudar a otros a entender por qué esto es a veces un requisito, aquí está mi ejemplo:

Estoy construyendo un marco MVC para una aplicación, tengo una clase de controlador base, que se amplía para cada clase de controlador individual. Cada controlador tendrá diferentes métodos, dependiendo de lo que el controlador necesite hacer. Por ejemplo, mysite.com/event cargaría el controlador de eventos. mysite.com/event/create cargará el controlador de eventos y llamará al método 'crear'. Para estandarizar la llamada de la función de creación, necesitamos la clase de controlador base para acceder a los métodos de la clase hija, que será diferente para cada controlador. Así código-sabia, tenemos la clase padre:

class controller { 

    protected $aRequestBits; 

    public function __construct($urlSegments) { 
     array_shift($urlSegments); 
     $this->urlSegments = $urlSegments;  
    } 

    public function RunAction($child) { 
     $FunctionToRun = $this->urlSegments[0]; 
     if(method_exists($child,$FunctionToRun)) { 
      $child->$FunctionToRun(); 
     } 
    } 
} 

A continuación, la clase hija:

class wordcontroller extends controller { 

    public function add() { 
     echo "Inside Add"; 
    } 

    public function edit() { 
     echo "Inside Edit"; 
    } 

    public function delete() { 
     echo "Inside Delete"; 
    } 
} 

Así que la solución en mi caso fue a pasar la instancia propio niño de nuevo a la clase padre como una parámetro.

+0

No necesita pasar la referencia $ child. method_exists ($ this, $ FunctionToRun)) debería ser suficiente. Tenga en cuenta que el wordcontroller hereda todas las funciones del controlador, por lo que wordControlObj-> runAction() comprobará las funciones existentes en las clases wordcontroller y controller. controlador, entonces se llamará a la versión del controlador de texto en su lugar. Si tiene un depurador, una forma fácil de rastrear el flujo de ejecución sería anular en el controlador de palabras el método simplemente usando: función RunAction() {parent :: RunAction() } – tanovellino

5

Desde PHP 5.3 puede usar la palabra clave static para llamar a un método de la clase llamada. es decir .:

<?php 
class A { 
    public static function who() { 
     echo __CLASS__; 
    } 
    public static function test() { 
     static::who(); // Here comes Late Static Bindings 
    } 
} 

class B extends A { 
    public static function who() { 
     echo __CLASS__; 
    } 
} 

B::test(); 
?> 

El resultado del ejemplo sería: B

fuente: PHP.net/Late Static Bindings

+0

genial, no puedo agradecerle lo suficiente. Estaba atrapado con mis clases estáticas donde no tengo una instancia de ellas para llamar, esta fue la única forma en que lo resolví – azerafati

+0

'static' hará que el código se ralentice – TomSawyer

+0

@TomSawyer ¿puede proporcionar alguna prueba o algún resultado de referencia? – merkjs

24

bien, esta respuesta es muy tarde, pero ¿por qué no pensar en nadie de esto?

Class A{ 
    function call_child_method(){ 
     if(method_exists($this, 'child_method')){ 
      $this->child_method(); 
     } 
    } 
} 

y el método se define en la clase que se extiende:

Class B extends A{ 
    function child_method(){ 
     echo 'I am the child method!'; 
    } 
} 

Así, con el siguiente código:

$test = new B(); 
$test->call_child_method(); 

la salida será:

I am a child method! 

I use esto para llamar a métodos de enlace que puede ser definido por una clase secundaria pero no tiene que serlo.

+2

Si todas las clases secundarias tienen los mismos métodos, también puede considerar implementar una interfaz para las clases secundarias. De este modo, puede excluir 'method_exists()' en la clase principal. – Ben

0

Es muy simple. Puedes hacer esto sin clase abstracta.

class whale 
{ 
    function __construct() 
    { 
    // some code here 
    } 

    /* 
    Child overridden this function, so child function will get called by parent. 
    I'm using this kind of techniques and working perfectly. 
    */ 
    function test(){ 
    return ""; 
    } 

    function myfunc() 
    { 
    $this->test(); 
    } 
} 

class fish extends whale 
{ 
    function __construct() 
    { 
    parent::construct(); 
    } 

    function test() 
    { 
    echo "So you managed to call me !!"; 
    } 

} 
0

Incluso si se trata de una cuestión de edad, esto es mi solución usando ReflectionMethod:

class whale 
{ 
    function __construct() 
    { 
    // some code here 
    } 

    function myfunc() 
    { 
    //Get the class name 
    $name = get_called_class(); 

    //Create a ReflectionMethod using the class and method name 
    $reflection = new \ReflectionMethod($class, 'test'); 

    //Call the method 
    $reflection->invoke($this); 
    } 
} 

La ventaja de utilizar la clase ReflectionMethod es que se puede pasar un array de argumentos y comprobar cuál es el necesaria en el método que está llamando:

//Pass a list of arguments as an associative array 
    function myfunc($arguments){ 
     //Get the class name 
     $name = get_called_class(); 

     //Create a ReflectionMethod using the class and method name 
     $reflection = new \ReflectionMethod($class, 'test'); 

     //Get a list of parameters 
     $parameters = $reflection->getParameters() 

     //Prepare argument list 
     $list = array(); 
     foreach($parameters as $param){ 

      //Get the argument name 
      $name = $param->getName(); 
      if(!array_key_exists($name, $arguments) && !$param->isOptional()) 
      throw new \BadMethodCallException(sprintf('Missing parameter %s in method %s::%s!', $name, $class, $method)); 

      //Set parameter 
      $list[$name] = $arguments[$name]; 
     } 

     //Call the method 
     $reflection->invokeArgs($this, $list); 
    } 
Cuestiones relacionadas