magento的rewrite機制和OOP的隱藏特性

在面向對象編程中,大家都知道類之間有重載(overload)、覆蓋(override)、隱藏(hide)三種關係,相信很多人對他們都已經很瞭解了,所以今天分析的重點也不是這些,而是magento中的rewrite機制,爲什麼會先提一下oop的三種特性呢,因爲我覺得他們和magento的rewrite機制很相似,但相似並非相同,還是先看下代碼吧,比較容易理解。

Magento發郵件時,使用的是內置的core/email_template,現在重寫這個model的send function,在config.xml添加如下內容:

		<models>
			<core>
				<rewrite><email_template>Company_Mymodel_Model_Email_Template</email_template>
				</rewrite>
			</core>
		</models>

然後Company/Mymodel/Model/Email/Template.php添加如下代碼:

class Company_Mymodel_Model_Email_Templateextends Mage_Core_Model_Email_Template {
        
   public function send($email, $name=null, array $variables = array()) {
             //省略,重點不在如何重寫send
        }

發郵件時可以這麼寫:

$mailConfirm = Mage::getModel('core/email_template');

$mailConfirm->send(//參數…);

或者

$mailConfirm = Mage::getModel(mymodel /email_template');

$mailConfirm->send(//參數…);


注意調用時的區別(紅色字體),一個仍然是調用內置的model,一個是重寫的model,你能猜到結果是什麼嗎?沒錯,結果永遠都是調用Company_Mymodel_Model_Email_Template的send函數。是不是有點像開頭提到的隱藏特性,因爲給人的感覺就是Company_Mymodel_Model_Email_Template的send吧core的send給隱藏了,我沒有說是和覆蓋相似,my god,算了還是先貼下三種特性的定義,好好體會下:

/////////////////////////////////////////////////////////////////////////////

重載 是指不同的函數使用相同的函數名,但是函數的參數個數或類型不同。調用的時候根據函數的參數來區別不同的函數。

成員函數被重載的特徵
(1)相同的範圍(在同一個類中); 
(2)函數名字相同; 
(3)參數不同; 
(4)virtual 關鍵字可有可無。

覆蓋(也叫重寫)是指派生類函數覆蓋基類函數 是指在派生類中重新對基類中的虛函數(注意是虛函數)重新實現。即函數名和參數都一樣,只是函數的實現體不一樣。

 特徵是
(1)不同的範圍(分別位於派生類與基類); 
(2)函數名字相同; 
(3)參數相同; 
(4)基類函數必須有virtual 關鍵字。 

“隱藏”是指派生類的函數屏蔽了與其同名的基類函數 是指派生類中的函數把基類中相同名字的函數屏蔽掉了。隱藏與另外兩個概念表面上看來很像,很難區分,其實他們的關鍵區別就是在多態的實現上。什麼叫多態?簡單地說就是一個接口,多種實現吧。

 規則如下
(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數將被隱藏(注意別與重載混淆)。 
(2)如果派生類的函數與基類的函數同名,並且參數也相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隱藏(注意別與覆蓋混淆) 
3種情況怎麼執行:1。重載:看參數2。隱藏:用什麼就調用什麼3。覆蓋:調用派生類

///////////////////////////////////////////////////////////////////////////////

因爲這裏的兩個send 名稱 參數 返回值都相同,並且基類的send沒有virtual限定,所以我說是和隱藏相似。爲什麼只說相似呢?調用的時候,對於隱藏特性,用什麼就調用什麼,比如用父類的,就new 父類的對象,用子類,就new子類。但是magento的rewrite 並不是,比如上邊寫到的兩種調用send的方法,一個是getModel的core(即父類),一個是getModel的繼承類,按理說應該會調用不同的send,但結果調用的永遠都是重寫的send。

通過跟蹤magento源碼發現,在Mage_Core_Model_Config的getGroupedClassName方法中:

        $config = $this->_xml->global->{$groupType.'s'}->{$group};

        if(isset($config->rewrite->$class)) {

            $className= (string)$config->rewrite->$class;

        } else {

        //。。。。。。

        }

在Mage::getModel('core/email_template')的時候,Magento先做了一個判斷,因爲在前邊的config裏已經對coremodel email_template進行了rewrite,所以儘管調用的是core的send,執行的仍然是rewrite後的send,假如是隱藏的話,調用core的send,執行的就應該是core的send;所以假如你曾經rewrite過core的email_template,或者是有其他第三方組件rewrite過(當然前提你可能不知道或者忘記了),調試的時候,在core的email_template裏改來改去,就是沒反應,並且很疑惑,根據oop的隱藏規則,我也是使用Mage::getModel('core/email_template')來調用的,new的core/ email_template,怎麼在core/ email_template修改就是沒反應呢?因爲我之前就碰到過這個問題。殊不知這裏根本沒有遵循OOP的隱藏原則,因爲已經被magento的rewrite機制給改掉了。

 

本文將隱藏特性和rewrite機制放在一起討論,就是希望能對二者有一個更好的理解

本文鏈接:http://blog.csdn.net/shangxiaoxue/article/details/7519423

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章