我已经问了一个类似的问题,但它更多地与使用裸字功能有关。基本上,我正在重构我的一些代码,因为我已经开始在perl中学习“package”和OOP。由于我的模块都没有使用“软件包”,所以我可以将它们“需要”到我的代码中,并且我能够毫无困难地使用它们的变量和函数。但是现在我创建了一个模块,我将其用作对象操作的类,我希望能够以相同的方式继续在其他模块中使用我的函数。没有多少阅读文档和教程已经完全回答了我的问题,所以,如果有人可以提供有关它如何工作的解释,以及为什么,那将会有很长的路要走,不仅仅是“这就是你如何做” - 类型答案。
也许这可以说明问题:
myfile.cgi:
require 'common.pm'
&func_c('hi');
print $done;
common.pm:
$done = "bye";
sub func_c {print @_;}
按预期,将打印“hi”然后“bye”。
myfile_obj.cgi:
use common_obj;
&func_obj('hi');
&finish;
common_obj.pm:
package common_obj;
require 'common.pm';
sub func_obj {&func_c(@_);}
sub finish {print $done;}
给出“Undefined subroutine func_c ...”
我知道(有点)关于命名空间等等,但我不知道如何实现我想要的结果(让func_obj能够从common.pm调用func_c)而不必修改common.pm (这可能会打破一堆依赖于它的其他模块和脚本的工作方式)。我知道在BEGIN中使用被称为“require”及其import()..但同样,这需要修改common.pm。我想要完成的是什么?
答案 0 :(得分:2)
您需要导出来自包common_obj的符号(它不是现有的类包)。
您需要熟悉Exporter模块。 Modern Perl也有介绍(免费提供书籍,但也考虑购买)。
这很简单 - 如果你在@EXPORT_OK
列出功能,那么use
你的包裹可以使用它们。您还可以通过EXPORT_TAGS
将功能组合到命名组中。
首先导出几个函数,列出use
语句中的函数并获取基础知识。这很容易。
如果您的模块确实是面向对象的,那么您将通过对象引用$my_obj->some_method(123)
访问这些方法,因此无需导出。一个软件包甚至可以提供过程/功能和面向对象的接口。
你想要用旧的东西包装旧的“不安全”模块似乎是一种合理的方式来继续前进。在不破坏现有工作代码的情况下控制事物。
编辑:解释。
如果您需要一段不合格的代码,那么它的定义将最终出现在需求包(common_obj)中,但如果您将代码限制在包定义中,然后use
,则需要显式导出定义。
答案 1 :(得分:1)
您可以使用common_obj :: func_obj和common_obj :: finish。您只需添加其命名空间即可。你不需要'&'在这种情况下。
当您使用package语句(在common_obj.pm中)时,您更改了后续函数的命名空间。如果没有(在common.pm中),则将函数包含在同一名称空间(main或common_obj)中。我不相信这与use / require有任何关系。
您应该使用Exporter。将common_obj更改为添加:
use base Exporter;
@EXPORT_OK = qw/func_obj finish/;
然后更改myfile_obj:
use common_obj qw/func_obj finish/;
我假设您只是尝试将新界面添加到旧的“正常工作”模块中。我确信这充满了问题,但如果可以做到这就是一种方法。
答案 2 :(得分:1)
您正在努力使用套餐,因为这将在未来为您提供很多帮助。为了实现这一目标,我建议您也开始重构旧代码。我可以理解不想触及任何旧的cgi文件,并且现在同意这个选择。但是您需要编辑一些包含的模块以获得您想要的位置。
使用您的示例作为基线,目标是保留myfile.cgi和所有类似的文件,而不做任何更改,但其他一切都是公平的游戏。
步骤1 - 创建一个新包,以包含common.pm
中的函数和变量common.pm需要是一个包,但是如果不影响你的旧代码就无法实现。解决方法是创建一个全新的包来包含旧文件中的所有函数和变量。这也是为所有当前和将要创建的包创建更好的命名约定的好机会。我假设你可能没有将它命名为common.pm,但无论如何,你应该选择一个目录并命名你的项目。我将为以前在common.pm
中保存的函数和变量随机选择名称MyProject :: Corepackage MyProject::Core;
@EXPORT = qw();
@EXPORT_OK = qw($done func_c);
%EXPORT_TAGS = (all => [@EXPORT, @EXPORT_OK]);
use strict;
use warnings;
our $done = "bye";
sub func_c {
print @_, "\n";
}
1;
__END__
这个新包应该放在MyProject / Core.pm中。您需要在EXPORT_OK列表中包含要导出的所有变量和函数。另外,作为一个小注释,我在示例中为所有打印语句添加了返回字符,以便于测试。
其次,编辑common.pm文件以包含以下内容:
use MyProject::Core qw(:all);
1;
__END__
你的myfile.cgi应该像现在一样工作。在继续之前确认这一点。
接下来,您可以开始创建新的包,这些包将依赖于旧的common.pm中的函数和变量。您的示例common_obj.pm可以重新编码为以下内容:
package common_obj;
use MyProject::Core qw($done func_c);
use base Exporter;
@EXPORT_OK = qw(func_obj finish);
use strict;
use warnings;
sub func_obj {func_c(@_);}
sub finish {print "$done\n";}
1;
__END__
最后,myfile_obj.cgi被重新编码为so:
use common_obj qw(func_obj finish);
use strict;
use warnings;
func_obj('hi');
finish();
1;
__END__
现在,我可以使用@EXPORT代替@EXPORT_OK来自动导出所有可用的函数和变量,但更好的做法是只选择性地导入您实际需要的那些函数。此方法还使您的代码更加自我记录,因此有人查看任何文件,可以搜索以查看特定函数的来源。
希望这有助于您开始更好的编码实践。重构旧代码可能需要很长时间,但是不断更新技能和工具绝对值得一提。