PHP: как вызвать функцию дочернего класса из родительского класса


Как вызвать функцию дочернего класса из родительского класса? Рассмотрим это:

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 !!";
  }

}
11 51

11 ответов:

что это абстрактные классы для. Абстрактный класс в основном говорит: тот, кто наследует от меня, должен иметь эту функцию (или эти функции).

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();

хорошо, этот ответ очень поздно, но почему никто не подумал об этом?

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

и метод определяется в расширяющемся классе:

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

так со следующим кодом:

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

вывод будет:

I am a child method!

Я использую это, чтобы вызвать методы крючка, которые можете определяется дочерним классом, но не обязательно.

технически вы не можете вызвать экземпляр fish (дочерний) из экземпляра whale (Родительский), но поскольку вы имеете дело с наследованием, myFunc () будет доступен в вашем экземпляре fish в любом случае, поэтому вы можете вызвать $yourFishInstance->myFunc() напрямую.

если вы ссылаетесь на шаблон метода pattern, тогда просто напишите $this->test() как тело метода. Звоню myFunc() С экземпляра рыбы делегирует вызов test() экземпляра рыбы. Но опять же, нет вызова от экземпляра кита к экземпляру рыбы.

замечание, что кит-Это млекопитающее, а не рыба ;)

Ок, ну есть так много вещей неправильно с этим вопрос я не знаю, с чего начать.

во-первых, рыба не киты и киты не рыба. Киты-это млекопитающие.

В-третьих, в PHP вы могли бы просто сделать:

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

В экземпляр whale это вызовет ошибку. В экземпляре fish он должен работать.

начиная с PHP 5.3 вы можете использовать ключевое слово static для вызова метода из вызываемого класса. т. е.:

<?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();
?>

приведенный выше пример будет выводить: B

источник:PHP.net / поздние статические привязки

Я бы пошел с абстрактным классом....
но в PHP вы не обязательно используйте их, чтобы заставить его работать. Даже вызов конструктора родительского класса является" нормальным " вызовом метода, и объект полностью "работает" на этом этапе, т. е. $this "знает" обо всех членах, унаследованных или нет.

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;

печать

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

т. е. даже если класс Foo ничего не знает о функции init() он может вызвать метод, так как поиск основан на том, что $this является ссылкой.
Это техническая сторона. Но вы действительно должны обеспечить реализацию этого метода, либо сделав его абстрактным (заставляя потомков реализовать его), либо предоставив реализацию по умолчанию, которая может быть перезаписана.

Я знаю, что это, вероятно, немного поздно для вас, но я должен был обойти эту проблему, а также. Чтобы помочь другим понять, почему это иногда требуется, вот мой пример:

Я создаю структуру MVC для приложения, у меня есть базовый класс контроллера, который расширяется каждым отдельным классом контроллера. Каждый контроллер будет иметь различные методы, в зависимости от того, что контроллер должен сделать. Например, mysite.com/event загрузил бы контроллер событий. mysite.com/event/create загрузит контроллер событий и вызовет метод 'create'. Чтобы стандартизировать вызов функции create, нам нужен базовый класс контроллера для доступа к методам дочернего класса, которые будут отличаться для каждого контроллера. Таким образом, с точки зрения кода, у нас есть родительский класс:

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();
        }
    }   
}

затем дочерний класс:

class wordcontroller extends controller {

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

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

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

поэтому решение в моем случае состояло в том, чтобы передать сам дочерний экземпляр обратно в родительский класс в качестве параметра.

единственный способ сделать это будет через отражение. Однако рефлексия стоит дорого и должна использоваться только в случае необходимости.

истинная проблема здесь заключается в том, что родительский класс не должен опираться на метод класса ребенка. Это руководящий принцип УД, и указывает на то, что есть серьезный недостаток в вашем дизайне.

Если ваш родительский класс зависит от конкретного ребенка, то она не может быть использована любой другие дочерние классы, которые могут расширить его, а также. Отношения родитель-ребенок идут от абстракции к конкретности, а не наоборот. Вам было бы намного лучше поместить требуемую функцию в родительский класс вместо этого и переопределить ее в дочерних классах, если это необходимо. Что-то вроде этого:

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

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

Это очень просто. Вы можете сделать это без абстрактного класса.

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 !!";
  }

}

даже если это старый вопрос, это мое решение с помощью 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);
  }
}

преимущество использования класса ReflectionMethod заключается в том, что вы можете передать массив аргументов и проверить, какой из них необходим в вызываемом методе:

    //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);
    }

Что делать, если кит не продлен? к чему приведет этот вызов функции? К сожалению, нет никакого способа сделать это.

О, а рыба вытягивает кита? Рыба-это рыба, кит-Это млекопитающее.