2009-12-22 126 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); 
    }