可能重複:(!)
In Perl, how can I check from which module a given function was imported?如何判斷Perl方法屬於哪個包?
我與一些舊代碼,其中一個以上的XML解析模塊已經use
d工作。
這意味着具有相同名稱的方法相互踩踏。
是否有一種簡單的方法來判斷特定方法屬於哪個包?
可能重複:(!)
In Perl, how can I check from which module a given function was imported?如何判斷Perl方法屬於哪個包?
我與一些舊代碼,其中一個以上的XML解析模塊已經use
d工作。
這意味着具有相同名稱的方法相互踩踏。
是否有一種簡單的方法來判斷特定方法屬於哪個包?
簡單且最可能正確的答案是,導出給定函數的最後一個模塊將是使用其功能的模塊。
當一個函數(或其他符號)被導出時,接收包的符號表被修改。因此,如果兩個導入函數對錶進行更改,則最後的更改將保留。
回想一下,use Foo;
是或多或少相當於BEGIN { require Foo; Foo->import if Foo->can(import); }
。
由於import
只是一個帶有特殊名稱的子程序,唯一的限制是J. Random Hacker的扭曲想象。 import
可以是任何代碼。它可以做任何事或不做任何事。例如,它可能包含邏輯以確保沒有已定義的函數被覆蓋。
但是,除了任何古怪,最後加載將是使用中的一個。
爲100%技術上正確,use Foo;
相當於BEGIN { require Foo; Foo->import; }
。
除了這個代碼不能像你所期望的那樣工作。
確切的代碼與我的例子不同。
上面的代碼做了什麼與方法解析在Perl中的工作方式有關。
通常,到Foo->some_sub
一個呼叫,其中some_sub
不存在和AUTOLOAD
功能Foo
定義,some_sub
將由AUTOLOAD
函數處理。 import
有一個特殊情況,可免除AUTOLOAD
檢查。見perlsub on Autoloading。
AUTOLOAD
已經(或確實沒有)被檢查後,我們檢查繼承。對於原包裝@ISA
中的每個項目,重複匹配功能或AUTOLOAD
函數的相同檢查。這是一個遞歸的過程,包括父母的父母等等,直到整個繼承樹被選中 - @ISA
被檢查從左到右,深度第一順序。所有這一次AUTOLOAD
例外都已到位,它將被跳過import
。
最終,如果找不到匹配的方法,我們就回到UNIVERSAL
通用基類。如果該函數存在於UNIVERSAL
中,則調用該函數,否則會拋出一個異常,表示無法找到該函數。
因此,在我們的Foo->import;
調用的情況下,調用UNIVERSAL::import
來處理作業。那麼,這個功能是做什麼的?
在Perl 5.12.2的代碼如下所示:
sub import {
return unless $_[0] eq __PACKAGE__;
return unless @_ > 1;
require warnings;
warnings::warnif(
'deprecated',
'UNIVERSAL->import is deprecated and will be removed in a future perl',
);
goto &Exporter::import;
}
注意,功能做的第一件事是擺脫困境,如果它不叫上UNIVERSAL
。
現在的一切,我說的是真的,只要你不要做幾件事情:
覆蓋的方法解析順序。如果你這樣做,然後方法的解決將發生,但你已經定義它。無論我們是否達到UNIVERSAL,或者什麼時候完全在空中,並受到你的突發奇想。
覆蓋UNIVERSAL::import
。你可以猴子修補程序UNIVERSAL :: import來做任何你想要的。再次,這將如何表現完全取決於你的心血來潮。
因此,上面給出的半等效代碼僅僅是發生什麼的簡寫。我認爲這會更容易理解,因爲它不需要知道Perl如何處理事情的很多細節,但它不是100%等同於真正發生的事情。做出意想不到的事情打破了等值。
凡我代碼完全等效代碼
變化。此外,我的代碼調用Foo->can
一般回落到UNIVERSAL::can
。 can
無法在正常的事件鏈中調用。當考慮到Perl中的can
問題時,這會變得特別多毛。
can
可能會被繼承圖中的任何類所覆蓋或重新實現。其中can
被調用受制於方法解析順序。多重繼承的所有問題都適用於此。can
未看到自動加載功能。由於自動加載不適用於導入,因此這可能不是什麼大不了的事情。問題是,如果您使用自動加載,則認爲將can
重新考慮在內是一種很好的做法。所以,這會增加上述問題。最好的方法是使用非核心模塊NEXT
來啓用重新分派方法,以便可以由鏈中的每個模塊處理。不幸的是,這很少完成。結論
所有這是很多來啃的地獄。
你可以接受我的速記,知道在某些情況下,它不完全正確。
或者你可以接受實際的代碼,它有自己的一套例外。
無論哪種方式,如果你突破了任何一個例子的表面,都有一些細微的問題需要解決。
無需檢查是否可以導入,如果在Foo – MkV 2010-11-27 11:43:26
@rafl:Thahks找到相關的問題。將關閉這個問題。 – Zaid 2010-11-27 11:21:12