2009-04-23 19 views
2

請看下面的代碼片段:PHP:在繼承鏈的每個對象的上下文中調用方法

<?php 

class A { 
     function fn() { 
       print 'Context: Class:' . get_class($this) 
         . ' Parent:' . get_parent_class($this) . "\n"; 
       if(get_parent_class($this)) { 
         parent::fn(); 
       } 
     } 
} 

class B extends A { } 
class C extends B { } 

$a = new A(); 
$c = new C(); 

$a->fn(); 

print "\n"; 

$c->fn(); 

?> 

運行它會得到以下輸出:

Context: Class:A Parent: 

Context: Class:C Parent:B 

Fatal error: Cannot access parent:: when current class scope has no parent in /home/andrei/test/test.php on line 10 

我相信它應該是這樣的:

Context: Class:A Parent: 

Context: Class:C Parent:B 
Context: Class:B Parent:A 
Context: Class:A Parent: 

做什麼您認爲?如果get_parent_class($this)返回非假值,我們應該安全地假設parent ::已定義嗎?在什麼類上下文中調用fn()

+0

輸出的是什麼(new B()) - > fn()產生? – 2009-04-23 14:51:42

+0

同樣的錯誤: 語境:等級:B父:一個 致命錯誤:無法訪問父::當電流類範圍在/home/andrei/test/test.php – 2009-04-23 14:55:16

+0

無父我覺得冠軍應該改變到更具描述性的一個。 – 2009-04-23 15:39:03

回答

3

使用parent ::或self ::的調用被認爲是靜態的。這些應該在定義類的上下文中進行評估,而不是在調用對象的範圍內。 PHP 5.3爲單詞靜態增加了一個新的含義,可用於靜態調用,如父母和自己,但將在調用類的上下文中評估。這稱爲後期靜態綁定。此頁面上的更多信息:

http://www.php.net/lsb

編輯:

經過一番思考,我相信這一行爲是完全可以接受的。首先,讓我們看看爲什麼A想讓它的foo()方法調用其父項的foo()方法,因爲A沒有父項。因爲它希望方法總是被執行而不管孩子的實施。如果是這樣,還有其他的解決方案,不是很好,但:

class A 
{ 
    final public function __construct() 
    { 
     echo __METHOD__; 

     $this->foo(); 

     $init = array($this, 'init'); 
     $args = func_get_args(); 

     call_user_func_array($init, $args); 
    } 

    // init would be used as a pseudo-constructor in children 
    public function init() 
    {} 

    final private function foo() 
    { 
     echo __METHOD__; 
    } 
} 

class B extends A 
{} 

class C extends B 
{} 

$c = new C; 

如果你試圖做的是在鏈執行每FOO()方法,然後將其預期的行爲。如果有一個B :: foo()函數,那麼它將被執行,如果它包含對parent :: foo()的調用,那麼A :: foo()也會被執行。

所以,大概是parent :: foo()在某種程度上令人困惑。應該讀起來像(對不起,我找不到一個更好的例子)。

the_first_parent_in_the_inheritance_chain_which_has_a_foo_method :: foo的()

這就是你真正感興趣的,爲什麼你會想調用foo什麼()在B的情況下?我能想到的唯一原因就是從B那裏獲得私人成員。但是,那麼A怎麼知道私人成員B有什麼?它不能。您不能在A沒有聲明的A :: foo()成員中使用。除非A是抽象的並且定義了一些抽象方法。當然,A可以聲明該財產是私人的(B不能給予被覆蓋的成員低於父母的可見性,我們的目標是B應該有私人的)。 然後B重寫該屬性,使其成爲我們想要的私有。現在,如果你的代碼能夠工作,A或C將有權訪問B的私有成員,儘管它不應該。這違反了一條規則。

是否有任何情況需要您詢問的行爲?

+0

感謝您的快速回答。奇怪的東西! – 2009-04-23 15:53:42

+0

@Andrei,我已經用一些進一步的想法更新了我的答案。 – 2009-04-23 17:14:56

+0

我通過幫助朋友發現了這種行爲。現在我明白爲什麼事情是這樣的。感謝您的解釋。我想和你聊更多關於php和web應用程序的信息。如果您想聯繫[at] andreisavu [dot] ro,請聯繫我。再次感謝。 – 2009-04-23 19:54:02

1

我不是PHP的嚮導,但我猜想,這個問題是與父母靜態的

+0

我沒有對靜態方法進行調用。請參閱:http://www.php.net/keyword.parent – 2009-04-23 15:00:03

0

你能不能嘗試調用父 - > FN() 我從來沒有嘗試這樣的東西之前,但這將是我的第一個猜測..

+0

無法調用parent-> fn()。見:http://www.php.net/keyword.parent – 2009-04-23 14:59:30

+0

你是對的,我是無知的。我的錯。 – Jake 2009-04-23 15:16:00

1

從我自己的實驗提示您的問題,似乎parent ::被解析爲該語句所在的類的父級。請按照以下方式更改您的測試用例以查看此行爲:

<?php 
class Z { 
     function fn() { 
       print "This is Z\n"; 
     } 
} 

class A extends Z { 
     function fn() { 
       print 'Context: Class:' . get_class($this) 
         . ' Parent:' . get_parent_class($this) . "\n"; 
       if(get_parent_class($this)) { 
         parent::fn(); 
       } 
     } 
} 
class B extends A { } 
class C extends B { } 
$a = new A(); 
$c = new C(); 
$a->fn(); 
print "\n"; 
$c->fn(); 
?> 

我同意這樣做不直觀,可能是一個錯誤。

UPDATE: 有趣的東西,當你使用它來調用父,而不是發生了:

eval(get_parent_class($this). "::fn();"); 
+0

我相信這是一個錯誤,因爲函數應該在子類的上下文中調用。 – 2009-04-23 15:02:17

+0

看起來上下文從未按預期設置。 – 2009-04-23 15:11:45

1

了這個問題,以及

context:類:父:

context:類: C父級:B
致命錯誤:噹噹前類作用域在父類中沒有父類時,無法訪問父類:: PHPDocument3 on line

1

我認爲你想要做的是錯的。如果你的類C中定義了fn()函數,那麼它將永遠不會在類A中調用fn(),所以在說父:: fn bcoz時你沒有意義,父類不具有調用函數fn的功能,那麼它返回fn ()定義在A中。

但是,如果你想在當前對象上下文中使用$ this而不是父中的其他函數。 Herez代碼爲此。

<?php 

class A { 
     function fn() { 
       print 'Context: Function:'.__FUNCTION__.' Class:' . get_class($this) 
         . ' Parent:' . get_parent_class($this) . "\n"; 
       if(get_parent_class($this)) { 
         $this->fB(); 
       } 
     } 
} 

class B extends A { } 
class C extends B { 
     function fB(){ 
       print 'Context: Function:'.__FUNCTION__.' Class:' . get_class($this) 
         . ' Parent:' . get_parent_class($this) . "\n"; 
     } 
} 

$a = new A(); 
$c = new C(); 

$a->fn(); 

print "\n"; 

$c->fn(); 

?> 

**out put** 
Context: Function:fn Class:A Parent: 

Context: Function:fn Class:C Parent:B 
Context: Function:fB Class:C Parent:B 
相關問題