2009-12-22 45 views
48

如何从父类调用子类的函数? 考虑这个: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 !!"; 
    } 

} 
+0

我知道我已经把错误的类名称,但这只是一个例子,而不是我会在任何地方实现它的东西。 – Sarfraz 2009-12-22 08:31:43

+8

从逻辑上来看,'鱼'应该是父类,'鲸'是孩子;} – Strae 2009-12-22 11:50:51

+23

@DaNieL鲸鱼不是鱼。 – 2011-08-24 10:40:32

回答

87

这就是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(); 
+14

虽然正确,我认为他想做'$鲸鱼=新鲸; $ fish = new Fish;'然后'$ whale-> myfunc();'应该调用'$ fish-> test();'不知道$ fish存在。 – Gordon 2009-12-22 12:04:12

+0

+1,抽象方法通常是您的父类引用子类中的方法的问题的答案。如果戈登是正确的,而且你真的想做一些不同的/具体的事情,你应该澄清。否则,这应该被接受。 – philfreo 2009-12-26 04:40:57

+0

我也搜索了这个,但你的回答并没有提升我想要的:whale = new whale(); $ whale->试验(); :(所以我想到的一件事 - 当被称为鲸鱼控制器时,然后只是重定向到鱼控制器和调用,但不知何故感觉重定向是滞后的 – 2014-01-20 14:01:35

0

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

哦,还有一条鱼扩大了鲸鱼吗?鱼是鱼,鲸是哺乳动物。

+0

反正,我不明白你的答案,你能建议一个替代它吗? – Sarfraz 2009-12-22 08:09:23

+0

这是unlogic。如果这条鲸鱼没有上课,它就不会延长 - 因此没有办法从它那里调用。 – Thielicious 2016-09-29 17:51:42

8

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

首先,鱼不是鲸鱼,鲸鱼也不是鱼。鲸鱼是哺乳动物。其次,如果你想从父类中不存在的父类中调用一个子类中的函数,那么你的抽象是有严重缺陷的,你应该从头开始重新考虑它。

第三,在PHP中,你可以只是:

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

whale一个实例会导致错误。在fish的情况下,它应该工作。

+4

+1 for-首先,鱼不是鲸鱼,鲸鱼也不是鱼。鲸鱼是哺乳动物。 – 2014-04-25 22:35:13

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."; 
    } 
} 
+0

我怀疑它可以用反射来完成。鲸鱼必须在任何地方将Fish硬编码。 – Gordon 2009-12-22 08:28:31

+0

这是很好的信息:) – Sarfraz 2009-12-22 08:29:44

15

技术上讲,你不能从鲸鱼实例(父母)反正叫鱼实例(孩子),但因为你是在处理继承,myFunc的()会在你的鱼实例可用,所以你可以直接拨打$yourFishInstance->myFunc()

如果您是指template method pattern,那么只需将$this->test()作为方法体。从调用myFunc()鱼实例会将调用委托给鱼实例中的test()。但是,再次,没有从鲸鱼实例调用鱼的实例。

在一个旁注,鲸鱼是哺乳动物,而不是一条鱼;)

+0

这只是一个例子伙计,我不会在任何地方实现这些名称:) – Sarfraz 2009-12-22 08:30:50

2

我会去与抽象类....
但是在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() 

即即使类Foo不知道一个函数初始化任何东西()它可以调用方法,因为查找的依据是什么$,这是对...的引用。
这是技术方面。但是你真的应该强制执行该方法,方法是将其抽象化(迫使后代实现它)或者通过提供可以被覆盖的默认实现。

2

我知道这可能是有点晚了你,但我必须解决这个问题为好。为了帮助别人明白这是为什么有时要求,这里是我的例子:

我建立一个应用程序的MVC框架,我有一个基本的控制器类,它是由每个个体控制器类扩展。每个控制器都有不同的方法,具体取决于控制器需要做什么。例如,mysite.com/event会加载事件控制器。 mysite.com/event/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"; 
    } 
} 

所以在我的情况的解决方案是通过子实例本身回父类作为参数。

+0

你不需要传递$子引用。请记住,wordcontroller继承了控制器中的所有函数,所以wordControlObj-> runAction()将检查wordcontroller和控制器类中的现有函数。如果wordController重写了任何方法控制器,然后调用wordcontroller版本 如果你碰巧有一个调试器,一个简单的跟踪运行流程的方法将被wordcontroller覆盖,方法就是使用: function RunAction(){parent :: RunAction() } – tanovellino 2016-09-08 08:14:26

5

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

+0

太棒了,我无法感谢你,我被我的静态类卡住了,我没有他们的实例调用,这是只有我解决它的方法。 – azerafati 2015-07-23 10:58:14

+0

'static'会让代码变慢 – TomSawyer 2016-11-03 09:36:56

+0

@TomSawyer能为您提供任何证明或任何基准测试结果吗? – merkjs 2017-03-25 17:34:26

24

好吧,这个答案是非常晚的,但为什么没有人想到这一点?

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

如果所有的子类都有相同的方法,你也可以考虑实现一个接口到子类。因此你可以排除父类中的'method_exists()'。 – Ben 2013-12-19 13:16:25

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

} 
0

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