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

}

Ответ 1

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

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

Ответ 2

Хорошо, этот ответ ОЧЕНЬ поздний, но почему никто не подумал об этом?

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!

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

Ответ 3

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

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

На сиднейте, кит - это млекопитающее, а не рыба;)

Ответ 4

Хорошо, в этом вопросе так много чего не так. Я не знаю, с чего начать.

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

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

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

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

В случае whale это приведет к ошибке. В случае fish он должен работать.

Ответ 5

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

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

Вышеприведенный пример выводит: В

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

Ответ 6

Я бы пошел с абстрактным классом....
но в 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. Это техническая сторона. Но вы действительно должны внедрить реализацию этого метода, либо сделав его абстрактным (принуждая потомков к его реализации), либо предоставив реализацию по умолчанию, которая может быть перезаписана.

Ответ 7

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

Я создаю среду 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";
    }
}

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

Ответ 8

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

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

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

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

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

Ответ 9

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

Ответ 10

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

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

}

Ответ 11

Если существует метод в дочернем классе, метод будет вызван из родительского класса (в качестве необязательного обратного вызова, если существует)

<?php

    class controller
    {

        public function saveChanges($data)
        {
            //save changes code
            // Insert, update ... after ... check if exists callback
            if (method_exists($this, 'saveChangesCallback')) {
                $arguments = array('data' => $data);
                call_user_func_array(array($this, 'saveChangesCallback'), $arguments);
            }
        }
    }

    class mycontroller extends controller
    {

        public function setData($data)
        {
            // Call parent::saveChanges
            $this->saveChanges($data);
        }

        public function saveChangesCallback($data)
        {
            //after parent::saveChanges call, this function will be called if exists on this child
            // This will show data and all methods called by chronological order:
            var_dump($data);
            echo "<br><br><b>Steps:</b><pre>";
            print_r(array_reverse(debug_backtrace()));
            echo "</pre>";
        }
    }

$mycontroller = new mycontroller();
$mycontroller->setData(array('code' => 1, 'description' => 'Example'));

Ответ 12

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

О, и рыбка удлиняет кита? Рыба - это рыба, кит - млекопитающее.