导入require'd文件,就像它是一个use语句一样

时间:2010-09-07 11:16:24

标签: perl perl-module

我遇到使用配置文件中定义的常量的问题。 这是我的包裹:

package myPackage;
require "APIconfig.pl";
APIconfig::import(APIconfig);

use constant SERVICE_URL => APIconfig::SERVICE_URL();

配置如下所示:

package APIconfig;
use constant SERVICE_URL => 'http://api.example.org/blah';
1;

运行此代码时,出现以下错误:

Undefined subroutine &APIconfig::SERVICE_URL called at API.pl line 4.

我不能使用'use'而不是'require',因为这需要将配置文件命名为.pm,并且它在我们网络上的许多服务器上都被称为.pl。 如何在不重命名文件的情况下使用该包?

3 个答案:

答案 0 :(得分:7)

'use'和'require'有两个不同之处。其中一个会影响您当前的问题,另一个则不会。不幸的是,你正在解决一个没有效果的问题。

区别在于:

1 /'use'调用import()函数,'require'不调用。

2 /'use'在编译时发生,'require'在运行时发生。

你正在解决'require'没有通过显式调用它来调用import()的事实。这不起作用,因为您的模块不导出任何符号,并且没有import()子例程。

你没有解决'use'语句在运行时执行的事实。问题是“使用常量SERVICE_URL => APIconfig :: SERVICE_URL();”在编译时执行,并且'require'尚未运行,因此myPackage对APIconfig一无所知。

(令人讨厌的,hacky)解决方案是将'require'语句放入BEGIN块 - 强制它在编译时执行。您还需要删除对import()的调用,因为这会产生运行时错误(由于缺少子例程)。

我以前用过的测试文件如下:

$ cat APIconfig.pl 
package APIconfig;
use constant SERVICE_URL => 'http://api.example.org/blah';
1;

$ cat api.pl 
#!/usr/bin/perl

package myPackage;
BEGIN {
  require "APIconfig.pl";
}
# APIconfig::import(APIconfig);

use constant SERVICE_URL => APIconfig::SERVICE_URL();

print SERVICE_URL, "\n";
$ ./api.pl 
http://api.example.org/blah

真正的解决方案是将APIconfig重写为真实模块。你提示你知道这一点,但环境问题阻碍你采取这种方法。我强烈建议您尝试解决这些问题并正确处理。

答案 1 :(得分:2)

这可能不对 - 包import中没有子例程APIconfig。一旦您使用完整包路径访问符号名称,无论如何都不需要导出/导入。

解决方案是在require之前的编译时运行use constant。这有效:

package myPackage;
BEGIN {
    require "APIconfig.pl";
}

use constant SERVICE_URL => APIconfig::SERVICE_URL();

答案 2 :(得分:1)

如果是配置文件,请不要使其成为代码。我在 Mastering Perl 中有一整章关于这一点,CPAN上有许多模块可以帮助您处理几乎任何配置格式。

如果是代码,为什么不将它作为模块,以便您可以使用use。模块在另一个程序中更容易控制和操作。

最简单的解决方案是不要逆潮流的游戏。 :)

除此之外,use与:

相同
 BEGIN {
      require Module;
      Module->import;
      }

您只需对文件名及其定义的命名空间执行相同操作(只要文件中的代码看起来像模块):

 BEGIN {
      require "file.pl";  # defines SomeNamespace
      SomeNamespace->import;
      }