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

时间:2009-12-22 08:03:30

标签: 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::construct();
  }

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

}

13 个答案:

答案 0 :(得分:94)

这就是abstract classes的用途。一个抽象类基本上说:无论谁继承我,都必须具备这个功能(或这些功能)。

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

答案 1 :(得分:27)

好的,这个答案很晚,但为什么没有人想到这个?

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!

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

答案 2 :(得分:15)

从技术上讲,你不能从鲸实例(父)中调用fish实例(子),但由于你正在处理继承,myFunc()无论如何都会在你的fish实例中可用,所以你可以调用{{1}直接。

如果您正在引用template method pattern,那么只需将$yourFishInstance->myFunc()写为方法正文。从 fish实例调用$this->test()会将调用委托给fish实例中的myFunc()。但同样,没有从鲸鱼实例到鱼类实例的调用。

在旁注中,鲸鱼是哺乳动物而不是鱼;)

答案 3 :(得分:9)

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

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

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

第三,在PHP中你可以做到:

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

whale的实例中,它会导致错误。在fish的实例中,它应该有用。

答案 4 :(得分:6)

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

以上示例将输出: 乙

来源:PHP.net / Late Static Bindings

答案 5 :(得分:3)

我会选择抽象类.... 但是在PHP中你不必使用它们来使它工作。甚至调用父类的构造函数也是一个“正常”的方法调用,此时对象完全“可操作”,即$“知道”所有成员,是否继承。

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

即。即使 class Foo 函数init()一无所知,它也可以调用该方法,因为查找是基于$ this引用的。 /> 这是技术方面。但是你真的应该通过使它成为抽象(强制后代实现它)或提供可以覆盖的默认实现来强制执行该方法。

答案 6 :(得分:2)

我知道这对你来说可能有点晚了,但我也不得不解决这个问题。为了帮助其他人理解为什么这有时是一个要求,这是我的例子:

我正在为应用程序构建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";
    }
}

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

答案 7 :(得分:1)

你能做到这一点的唯一方法是通过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.";
  }
}

答案 8 :(得分:1)

即使这是一个老问题,这是我使用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);
    }

答案 9 :(得分:0)

这很简单。你可以在没有抽象类的情况下做到这一点。

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

}

答案 10 :(得分:0)

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

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

答案 11 :(得分:0)

鲸鱼 实例中,您无法调用此函数。但您可以从 实例

function myfunc()
{
    static::test();
}

答案 12 :(得分:-1)

如果鲸鱼没有延长怎么办?该函数调用会产生什么结果?不幸的是没有办法做到这一点。

哦,鱼是否延长了鲸鱼?鱼是鱼,鲸鱼是哺乳动物。