PHP:如何从父类调用子类的函数

PHP:如何从父类调用子类的函数,php,inheritance,Php,Inheritance,如何从父类调用子类的函数? 考虑这一点: 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::

如何从父类调用子类的函数? 考虑这一点:

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

}

如果鲸鱼没有延伸呢?那个函数调用会产生什么结果?不幸的是,没有办法做到这一点


哦,鱼会延伸鲸鱼吗?鱼是鱼,鲸鱼是哺乳动物

好吧,这个问题有太多问题,我真的不知道从哪里开始

首先,鱼不是鲸鱼,鲸鱼也不是鱼。鲸鱼是哺乳动物

其次,如果您想从父类中不存在的父类调用子类中的函数,那么您的抽象存在严重缺陷,您应该从头开始重新考虑它

第三,在PHP中,您可以执行以下操作:

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

whale
的实例中,它将导致错误。在
fish
的例子中,它应该可以工作。

唯一可以做到这一点的方法是通过。然而,反射是昂贵的,应该只在必要时使用

这里真正的问题是父类永远不应该依赖于子类方法的存在。这是面向对象设计的指导原则,表明您的设计中存在严重缺陷

如果父类依赖于特定的子类,则任何其他可能扩展它的子类都不能使用它。父子关系从抽象到具体,而不是相反。您最好将所需函数放在父类中,必要时在子类中重写它。大概是这样的:

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

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

从技术上讲,您不能从鲸鱼实例(父实例)调用鱼实例(子实例),但由于您处理的是继承,myFunc()在您的鱼实例中仍然可用,因此您可以直接调用
$yourFishInstance->myFunc()

如果您正在引用,那么只需编写
$this->test()
作为方法体。从fish实例调用
myFunc()
将把调用委托给fish实例中的
test()
。但同样,不要从鲸鱼实例调用鱼实例

另一方面,鲸鱼是哺乳动物而不是鱼;)

这就是我们的目的。一个抽象类基本上说:从我继承的人必须拥有这个函数(或这些函数)


我会选择抽象类……
但是在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()
i、 e.即使类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";
    }
}

因此,在我的例子中,解决方案是将子实例本身作为参数传递回父类

由于PHP5.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


来源:

好吧,这个答案已经很晚了,但是为什么没有人想到这个呢

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!

我用它来调用钩子方法,钩子方法可以由一个子类定义,但不一定是这样。

非常简单。您可以在没有抽象类的情况下实现这一点

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

如果子类中存在方法,则将从父类调用该方法(如果存在,则作为可选回调)

鲸鱼实例您不能调用此函数。但是从的例子中,你可以


不管怎样,我无法理解你的答案,你能建议一个替代方案吗?这是不符合逻辑的。如果鲸鱼没有子类,它就不会被扩展,因此没有方法从中调用。@Marius“鱼是鱼,鲸鱼是哺乳动物。”---这跟什么有什么关系?这是一个类名。代码有效吗?这才是真正的问题。因为你的回答可能只是一个评论(它没有试图以任何方式解决这个问题),而且因为你非常傲慢,我将对这个答案投反对票。我怀疑这是否可以通过反思来实现。Whale必须在某个地方对Fish进行硬编码。这只是一个示例,伙计,我不会在任何地方实现这些名称:)我知道我放置了错误的类名,但这只是一个示例,我不会在任何地方实现它。从逻辑上看,
fish
应该是父类,
whale
应该是子类;)@DaNieL也许fish应该是子类,因为它位于
    //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);
    }
<?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'));
function myfunc()
{
    static::test();
}