模块

    模块是你可以包含在另一个Perl文件(脚本或模块)中的一个文件,是与.plPerl脚本语法完全相同的文本文件。一个示例模块文件可能位于C:\foo\bar\baz\Demo\StringUtils.pm或者/foo/bar/baz/Demo/StringUtils.pm,并且有如下内容:

    因为模块在被加载时会自顶向下执行,你需要在结尾处返回一个true表示加载成功。

    为了让Perl解释器能够找到这些Perl模块文件,调用perl程序前,包含它们的目录名需要被添加到环境变量PERL5LIB中。列出包含这些模块的根目录,而不是其中的某些子目录或者模块本身:

    1. set PERL5LIB=C:\foo\bar\baz;%PERL5LIB%

    或者

    一旦Perl模块被创建并且perl知道如何找到它以后,你就可以使用内置函数[require](http://perldoc.perl.org/functions/require.html)在Perl脚本中查找并执行它。比如,调用require Demo::StringUtils使Perl解释器去逐个查找所有列在PERL5LIB中的目录,看是否有叫做Demo/StringUtils.pm的文件。我们的示例脚本可以叫做main.pl,并且包含以下内容:

    1. use strict;
    2. use warnings;
    3. print zombify("i want brains"); # "r wrnt brrrns"

    现在问题来了:如果main.pl包含很多require调用,而且每个被加载的模块又包含更多require调用,那我们要找到zombify()子程序最初的定义就太困难了。解决方案是使用包。

    是用来声明子程序的命名空间。所有的子程序默认都被声明在当前包中,而程序开始执行的时候,你位于main包中,不过你可以用内置函数[package](http://perldoc.perl.org/functions/package.html)来切换包:

    注意,我们这里使用双冒号::作为命名空间的分隔符。

    当你调用一个子程序的时候,你默认会调用当前包中的子程序。你也可以显示指定包的名字,我们继续上面的脚本,看看会发生什么:

    1. subroutine(); # "kingedward"
    2. main::subroutine(); # "universe"
    3. Food::Potatoes::subroutine(); # "kingedward"

    所以对上面描述的问题的一个符合逻辑的解决方案就是把C:\foo\bar\baz\Demo\StringUtils.pm或者/foo/bar/baz/Demo/StringUtils.pm改为:

    1. use strict;
    2. require Demo::StringUtils;
    3. print Demo::StringUtils::zombify("i want brains"); # "r wrnt brrrns"

    下面这些内容可要仔细阅读了。

    在Perl语言中包和模块是彼此独立完全不同的两个功能,它们恰好都是用双冒号作为分隔符根本就是个掩人耳目的把戏。在一个脚本或者模块中多次切换包是可行的,在不用位置的多个文件中使用同一个包名也是可行的。调用require Foo::Bar并不会去查找并且加载一个有package Foo::Bar的文件,也不一定会加载定义在Foo::Bar命名空间里的子程序。调用require Foo::Bar仅仅表示加载一个名为Foo/Bar.pm的问题,与其中有什么包的声明没有任何关系,也许那个文件中声明了package Baz::Qux和其他乱七八糟的内容。

    同样的,调用Baz::Qux::processThis()子程序并不一定要声明在名叫Baz/Qux.pm的文件里,它可能被定义在任何地方

    分离这两种功能可能是Perl中最糟糕的一个设计,而如果把它们视作分开的功能,将带来混乱,以及让人抓狂的代码。值得庆幸的是,主流的Perl程序员总是遵循下面两个规则:

    1. Perl脚本(.pl文件)不应该包含package声明。
    2. Perl模块(.pm文件)必须包含且仅包含一个package声明,且包名与它的文件名、所在的位置一致。例如,模块必须由package Demo::StringUtils开头。

    因此,你会发现实际工作中,绝大部分由可靠的第三方提供的“包”和“模块”的概念是可以交换混用的。然而,很重要的是,你千万不能把这个当做承诺,因为将来有一天你一定会碰上一个疯子写的代码。