设置Perl模块结构

Rus*_* C. 5 oop perl perl-module

我在弄清楚如何以一种面向对象的方式构造Perl模块时遇到了麻烦,因此我可以拥有一个带有多个子模块的父模块,并且调用脚本只会加载所需的特定子模块。例如,我希望能够像这样进行方法调用:

use Example::API;    
my $api = Example::API->new();

my $user = {};
$user->{'id'} = '12345';

$api->Authenticate();
$user->{'info'} = $api->Users->Get($user->{'id'});
$user->{'friends'} = $api->Friends->Get($user->{'id'});
Run Code Online (Sandbox Code Playgroud)

就文件结构而言,我想按如下所示设置模块,或采用任何使一切正常工作所需的结构:

api.pm
users.pm
friends.pm
...
Run Code Online (Sandbox Code Playgroud)

首先,我要这样做的原因是,如果某人只想根据API进行身份验证,则不必加载其他所有模块。同样,如果某人只想获取用户的信息,则不必加载friends.pm模块,只需加载即可users.pm。如果您能提供必要的示例Perl代码来设置每个模块,并解释如何设置文件结构,将不胜感激。如果我要完成所有尝试完成的工作都是错误的,我将对最佳方法的解释以及如何设置的示例代码表示感谢。

Eri*_*rom 3

从您的示例中,在您的主模块中,我假设您将提供访问器方法来获取子类。因此,您所要做的就是包含require Sub::Module;在该方法的顶部。编译时不会发生任何事情,但第一次运行代码时,perl 将加载该模块。第一次加载后,该行将require Sub::Module;变为空操作。

如果您的所有代码都是面向对象的,则无需担心导入函数。但如果您这样做,该语句use Module qw(a b c);将被解释为:

BEGIN {
    require Module;
    Module->import(qw(a b c));
}
Run Code Online (Sandbox Code Playgroud)

BEGIN使其在编译时发生,但没有什么可以阻止您在运行时使用内部结构。在运行时导入的任何子例程都必须用括号调用,并且原型将不起作用,因此除非您知道自己在做什么,否则运行时导入可能是一个坏主意。不过,运行时require和通过包方法进行访问是完全安全的。

所以你的$api->Users方法可能会像这样工作:

# in package 'Example::API' in the file 'Example/API.pm'

sub Users {
    require Example::API::Users;  # loads the file 'Example/API/Users.pm'
    return  Example::API::Users->new( @_ ); # or any other arguments
}
Run Code Online (Sandbox Code Playgroud)

在上面的示例中,我展示了包名称及其所在文件之间的两种翻译。通常,所有内容::都会更改为/.pm添加到末尾。然后perl将在全局变量的所有目录中搜索该文件@INC。您可以查看require的文档以了解所有详细信息。

更新:

缓存此方法的一种方法是在运行时将其替换为仅返回值的函数:

sub Users {
    require Example::API::Users;
    my $users = Example::API::Users->new;

    no warnings 'redefine';
    *Users = sub {$users};

    $users
}
Run Code Online (Sandbox Code Playgroud)