PHP: Как вызвать функцию дочернего класса из родительского класса - PullRequest
54 голосов
/ 22 декабря 2009

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

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

}

Ответы [ 12 ]

97 голосов
/ 22 декабря 2009

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

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();
27 голосов
/ 27 января 2013

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

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!

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

15 голосов
/ 22 декабря 2009

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

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

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

9 голосов
/ 22 декабря 2009

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

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

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

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

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

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

6 голосов
/ 05 января 2013

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

<?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 / Поздние статические привязки

3 голосов
/ 22 декабря 2009

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

2 голосов
/ 20 февраля 2012

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

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

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

1 голос
/ 11 декабря 2017

Даже если это старый вопрос, это мое решение с использованием 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);
    }
1 голос
/ 22 декабря 2009

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

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

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

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

class fish extends whale
{
  function myfunc()
  {
     echo "I am always a fish.";
  }
}
0 голосов
/ 22 мая 2019

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

<code><?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 "
"; } } $ mycontroller = new mycontroller (); $ mycontroller-> setData (array ('code' => 1, 'description' => 'Example'));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...