代码之家  ›  专栏  ›  技术社区  ›  Zaid

如何判断Perl方法属于哪个包?[副本]

  •  0
  • Zaid  · 技术社区  · 15 年前

    可能重复:
    In Perl, how can I check from which module a given function was imported?

    我正在处理一些旧代码,其中有多个(!)XML分析模块 use d.

    这意味着同名的方法互相践踏。

    有没有一个简单的方法来判断一个特定方法属于哪个包?

    1 回复  |  直到 15 年前
        1
  •  1
  •   daotoad    15 年前

    最简单也是最可能正确的答案是,最后一个导出给定函数的加载模块将是使用该函数的模块。

    导出函数(或其他符号)时,将修改接收包的符号表。因此,如果两个导入函数对表进行了更改,则最后一个更改是保留的。

    回想一下 use Foo; 是 或多或少 相当于 BEGIN { require Foo; Foo->import if Foo->can(import); } .

    自从 import 只是一个具有特殊名称的子程序,唯一的限制是J.Random黑客的扭曲想象。 进口 可以是 任何 代码。它可以做任何事,也可以不做任何事。例如,它可以包含逻辑,以确保没有已经定义的函数被重写。

    但是,除非有任何奇怪的地方,最后一个装载的将是使用中的那个。


    100%技术正确, 使用foo; 等于 BEGIN { require Foo; Foo->import; } .

    但这段代码并不像您期望的那样工作。

    具体的代码与我的示例不同。

    上面的代码所做的工作与Perl中方法解析的工作方式有关。

    通常,一个电话 Foo->some_sub 哪里 some_sub 不存在并且 AUTOLOAD 函数在中定义 Foo , 一些潜水艇 将由 自动加载 功能。有一个特殊的案例 进口 免除了它 自动加载 检查。见 perlsub on Autoloading .

    后 自动加载 已经(或者真的没有)被检查过,我们检查继承。对匹配函数或 自动加载 对原始包中的每个项重复函数 @ISA . 这是一个递归过程,包括父代的父代等等,直到检查整个继承树为止。-- “伊萨” 从左到右,深度优先。一直以来, 自动加载 异常已存在,将跳过 进口 .

    最后,如果找不到匹配方法,我们就放弃了 UNIVERSAL 通用基类。如果函数存在于 通用 ,它被调用,否则我们抛出一个异常,说明找不到函数。

    所以,在我们的情况下 Foo->import; 呼叫, UNIVERSAL::import 调用以处理该作业。那么,这个函数是做什么的?

    在Perl5.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;
    }
    

    请注意,函数所做的第一件事是,如果没有调用它,它将退出。 通用 .

    现在我所说的一切都是真的,只要你不做几件事:

    • 重写方法解析顺序。如果您这样做,那么无论您如何定义方法解析,都会发生。无论我们是否走向宇宙,或者什么时候完全在空中,并服从于你的奇想。

    • 覆盖 通用::导入 . 您可以通过monkey补丁universal::import来做任何您想做的事情。再说一次,这种行为完全取决于你的一时冲动。

    所以,我上面给出的半等价代码只是一个简单的简写。我认为这会更容易理解,因为它不需要知道Perl是如何做事情的那么多细节,但是它并不完全等同于实际发生的事情。做一些意想不到的事情会破坏等价性。

    我的代码与完全等效的代码不同

    此外,我的代码调用 Foo->can 通常会回到 UNIVERSAL::can . 在任何地方都不是 can 在正常的事件链中调用。当我们考虑到 可以 在Perl中。

    • 可以 可以被继承图中的任何类重写或重新实现。哪个 可以 调用的对象取决于方法解析顺序。所有多重继承的问题都适用于这里。
    • 可以 看不到自动加载的函数。由于自动加载不适用于导入,这看起来可能不是什么大问题。问题是超载被认为是良好的做法 可以 如果使用自动加载,请考虑到这一点。所以,这使上述问题更加复杂。最好是使用非核心模块 NEXT 启用方法重新分配,以便链中的每个模块都可以处理该方法。不幸的是,这很少发生。

    结论

    所有这些都是一件非常值得咀嚼的事情。

    你可以接受我的速记,知道在某些情况下,它是不完全正确的。

    或者您可以接受具有自己的异常集的实际代码。

    不管怎样,如果你突破了这两个例子的表面,就会有一些微妙的问题需要处理。

    推荐文章