【发布时间】:2018-04-06 11:31:23
【问题描述】:
我知道之前已经回答过这个问题的具体实例:
- How can I dynamically include Perl modules without using eval?
- How do I use a Perl package known only in runtime?
Perl Monks 也有很好的答案:
但我想要一种向 Perl 应用程序添加功能的可靠方法:
- 高效:如果不需要代码,则不应编译。
- 易于调试:如果动态代码出现问题,则错误报告,应指向动态代码的正确位置。
- 易于扩展:添加新代码应该像添加新文件或目录+文件一样简单。
- 易于调用:主应用程序应该能够轻松使用“插件”。一个有效的机制来检查“插件”是否已经加载,如果没有加载,将是一个加号。
为了说明这一点,以下是一些可以从一个好的解决方案中受益的示例:
一组从不同应用程序移动数据的脚本。例如,将数据从 OpenCart 移动到 Prestashop,其中数据模型中的每个 entity 都有一个特定的“附加组件”来处理输入或输出;然后中间数据模型负责数据的转换。这可用于向任何方向移动数据,甚至在同一电子商务的不同版本之间移动数据。
需要在不同位置呈现不同类型 HTML 的 Web 应用程序。每个“模块”都知道如何处理特定信息并接受参数来完成它。一个模块输出 HTML,另一个是文档列表,另一个是文档,另一个是横幅,等等。
这里有一些我用过的例子。
在运行时加载一个函数并输出可能的编译错误:
eval `cat $file_with_function`;
if( $@ ) {
print STDERR $@, "\n";
die "Errors at file $file_with_function\n";
}
或者使用File::Slurp 更健壮:
eval read_file("$file_with_function", binmode => ':utf8');
检查某个函数是否已经定义:
if( !defined &myfunction ) {
die "myfunction is not defined\n";
}
可以从那里调用该函数。这对一个功能来说很好,但对很多人来说不是。
如果函数放在模块中:
require $file_with_function; # needs the ".pm" extension, i.e. addon/func.pm
$name_of_module->import(); # need to know the module name, i.e. Addon::Func
$name_of_module->myfunction(...);
require 可以在eval 中受到保护,然后像以前一样使用$@。
load $name_of_module;
后跟import 并以相同的方式使用。 安全性不应成为问题,因为可以假定动态代码来自受信任的地方。有没有更好的方法?哪种方式会被视为良好做法?
如果有帮助,我将在 Dancer 框架内使用该解决方案(以及其他地方,但不限于)。
编辑:鉴于 cmets,我添加了更多信息。我想到的所有案例都有共同点:
- 有不止一个动态代码。一开始可能有很多。
- 每一位代码都有相同的接口。
【问题讨论】:
-
你想解决什么问题?
-
我举了两个例子,但可能不太清楚。问题是一种在不接触其代码的情况下向应用程序添加新功能的方法。例如,通过向新文件/目录添加新代码。
-
一个好的解决方案将允许应用程序知道它的新功能并使用它们,而应用程序的用户可能只能参考他们。
-
那是一种技术的应用。你说你不希望代码预先编译。为什么?你想在那里解决什么问题?在我看来,你在试图过度设计,但你最终会变得聪明过头,而且你会背负一大堆技术债务,你的同事会恨你。
-
require "dir/perlscript.NotPmExtension";不必是包内的代码。
标签: perl