1. 包

(1).将数据和函数包装到单独的命名空间中称为封装(encapsulation)。Perl中的包相当于C++中的命名空间,包的作用域是从包的声明到包含在最内层的块,包中的所有变量都有一个单独的符号表,同一包名下使用变量可以省略前缀。缺省包名的包也称main包。要引用其他包的变量或子程序要给出包名的前缀(变量不能是my或local的)。(当前包——main包在使用自己变量时可以取消包名)
例如:
package boy; #指定当前使用的包
#以下为boy包的内容
my $salary = undef;
subroutine mysub{  
local($myvar);  
#stuffgoeshere  
}  
...
 
package item;
#以下是item包的内容
my $price = 15.3;
...
 
引用其他包变量的方法: $item::variable #或者 $item'variable
引用boy包中的salary会出错,因为这一个my变量
引用子程序同理: $boy'mysub #或者 $boy::mysub
对于main包(当前包),可以$main::variable 或者 $::variable;
 
在Perl5中,可以用如下语句指定无当前Perl包:
package;
这时,所有的变量必须明确指出所属Perl包名,否则就无效--错误。
$mypack::var=21;#ok
$var=21; #error-nocurrentpackage
这种情况直到用package语句指定当前Perl包为止。
 
注意:如果程序仅是一个跨越多个包的过程型程序,那么Perl程序将按顺序执行,而不是只执行main包的内容。
$var1 = 1;
$var2 = 2;
print "in package main\n";
print "$main::var1, $main::var2\n";
print "$var1, $var2\n";
print "$p1'var1, $p1'var2\n";
printf("\n");
 
package p1;
$var1 = 10;
$var2 = 20;
print "in package p1\n";
print "$main::var1, $main::var2\n";
print "$var1, $var2\n";
print "$p1'var1, $p1'var2\n";
printf("\n");
 
package main;
print "in package main\n";
print "$main::var1, $main::var2\n";
print "$var1, $var2\n";
print "$p1'var1, $p1'var2\n";
printf("\n");
结果如下:
in package main
1, 2
1, 2 #缺省包名将显示本包中的$var1和$var2
, #这时p1中的变量还未定义
 
in package p1
1, 2
10, 20
10, 20
 
in package main
1, 2
1, 2
10, 20 #这时p1中的变量已定义
 
2. 符号表
每一个包都有一个符号表,符号表都存储在一个散列里,这个散列的名字跟该包的名字相同,只是后面还要多加两个冒号,例如main包符号表就是%main::。Perl使用符号表来把标识符(比如$a,去掉前缀的'a'字符串就是标识符)映射到相应的值。但是散列表不允许重复键值(比如@a, %a, $a都有相同的名称) , 所以我们不可能使散列表中拥有相同名字的两个条目指向两个不同的值。于是Perl在符号表和其他数据类型之间,放置了一个叫做typeglob的数据结构。typeglob是一种Perl脚本中的真实的数据类型(前缀*),是一组指向值的指针,其中每个指针对应!一种!值类型;所以tpyeglob本身可以看作一种散列,其中有不同类型的变量记录。
也可以这么讲:它是包含了各个名为b的变量的引用的hash结构,它叫做 *b 。
*b{SCALAR}=\$b; #指向名为b的标量类型
*b{HASH}=\%b; #指向名为b的哈希类型
*b{ARRAY}=\@b; #指向名为b的数组变量
这样就把名称和引用分开了,好处是方便取别名。例如*c=*b,那么b和c指向了同一块glob实体。*c{HASH}就是%b的地址。
 
当我们使用变量%b的解析过程:perl先在符号表中找到c所映射的glob,然后在glob中找到前缀为%的引用,最后返回存储位置。
 
main包中的符号表包含了当前的编译配置和环境信息,使用下面脚本得到:
foreach $Key  (%main::)
{
    printf("$Key: $main::{$Key}\n");
}
 
3. 模块
(1). 概念
Perl5将包的概念扩展到模块,模块存储在文件里的包,模块通常以.pm扩展名的包名。使用use或require函数获得require函数,将模块加载到脚本中。模块可以是面向过程的或面向对象的,文件名以大写字母开头(小写字母开头的.pm文件时特殊类型的模块,称为编译提示pragma,通常告诉编译器运行Perl要检查哪些条件)。
@INC数组包含了模块所在位置的目录路径,对于没有的目录也将其加入@INC中或者设置环境变量PERL5LIB来指定其他模块的路径。使用编译器选项perl -V可以查看所有相关信息,包括@INC。
Perl4没有模块(.pm)的概念,它的模块是以.pl为扩展名的Perl脚本。要引用这些库需要require函数,例如
require "mypackage.pl"
 
(2). use和require
这两个函数都是一个意思,加载和引用Perl的模或者是子程序。区别在于use是在当前默认的里面去寻找,一旦模块不在指定的区域内的化,用Perl use是不可以引入的
第一、Perl use引入的名称不需要后缀名(.pm),而require需要。
第二、Perl use语句是编译时引入的,require是运行时引入的。
第三,Perl use引入模块的同时,也引入了模块的子模块。而require则不能引入,要在重新声明。
use my;
my中包含了一个Module.pm
而require
则需要引入require my; 
require my::Module.pm;
如果不想让use引入Module.pm则可以用use require()一对括号来说明即可。
第四、用use引入模块是趋势,但是也不能说require没有存在的必要,视具体情况而定。
第五、跟require不同的是,use只能用于包含模块,也就是.pm文件。
use MyModule;
实际上,编译器将从@INC指定的目录下去寻找MyModule.pm模块。如果模块名称中包含::双冒号,该双冒号将作为路径分隔符,相当于Unix下的/或者Windows下
的。如:
use MyDirectory::MyModule;
编译器将从@INC指定的目录下的MyDirectory子目录去寻找MyModule模块,类似
如下路径:
C:\Perllib\MyDirectory
C:\Perlextlib\MyDirectory
C:\Perlsitelib\MyDirectory
另外,可以选择导入的内容,例如
use strict "vars"; This generates a runtime error if you use symbolic references
use strict "refs"; This generates a compile-time error if you access a variable that wasn't declared quilified with my, local, our.
use strict "subs"; This disables the poetry optimization, generating a compile-time error if you try to use a bareword identifier that's not a subroutine, unless it is a simple identifier (no colons) and that it appears in curly braces or on the left hand side of the => symbol.
第六:两个都是包含,但是包含的条件是不一样的。require包含是发生在程序运行期,而use包含是发生在编译期。学过C/C++的人比较容易理解。下面的例子是错误的:   
use Config;  
if($Config{'osname'} eq "MSWin32") {
use Win32Module;
else {
use UnixModule;
}
正因为use是发生在编译期,代码没有执行,所以$Config变量的值是无法判断的。在内部,Perl use其实调用了require和import静态函数。import()函数告诉包哪些特征将要被导入当前包中,这意味着用之前不必验证函数或者变量是否合法。而require是不会调用import()的。
第七:require函数
用require函数可以把程序分割成多个文件并创建函数库。例如,在myfile.pl中有定义好的Perl函数,可用语句require ("myfile.pl");在程序中包含进来。当Perl解释器看到这一语句,就在内置数组变量@INC指定的目录中寻找文件myfile.pl。如果找到了,该文件中的语句就被执行,否则程序终止并输出错误信息:
    Can't find myfile.pl in @INC
作为子程序调用参数,文件中最后一个表达式的值成为返回值,require函数查看其是否为零,若为零则终止。例如myfile.pl最后的语句是:
    $var = 0;
因为最后的语句值为零,Perl解释器输出下列错误信息并推出:
    myfile.pl did not reture true value
所以一般作为模块使用的.pl脚本以ture或者1结尾。
可以用简单变量或数组元素等向require传递参数,如:
@reqlist = ("file1.pl", "file2.pl", "file3.pl");
require ($reqlist[$0]);
require ($reqlist[$1]);
require ($reqlist[$2]);
还可以不指定文件名,即:
    require;
这时,变量$_的值即作为文件名传递给require。
注:如果@INC中有多个目录中含有同一个文件,则只有第一个被包含。
1、require函数和子程序库
    用require函数可以创建可用于所有Perl程序的子程序库,步骤如下:
a、确定存贮子程序库的目录
b、将子程序抽取放到单独的文件中,将文件放到子程序库目录
c、每个文件末尾加一句非零值的语句,最简单的办法是语句 1;
d、在主程序中用require包含一个或多个所需的文件。
e、运行主程序时,用 -I 选项指定子程序库目录,或者在调用require前将该目录添加到@INC数组中。
    例如:假设目录/u/perldir中存有你的Perl子程序库,子程序mysub存贮在文件mysub.pl中。现在来包含上该文件:
    unshift (@INC, "/u/perldir");
    require ("mysub.pl"); 对unshift的调用把目录/u/perldir添加到@INC数组,对require的调用将mysub.pl文件的内容包含进来作为程序的一部分。
注意:
1、应该使用unshift来向@INC中添加目录,而不是push。因为push增加到@INC的末尾,则该目录将被最后搜寻。(同use,它只会引用找到的第一个)
2、用require指定Perl版本
    Perl 5中,可以用require语句来指定程序运行所需的Perl版本。当Perl解释器看到require后跟着数字时,则只有其版本高于或等于该数字时才运行该程序。例如,下面语句表明只有Perl解释器为5.001版或更高时才运行该程序:
    require 5.001;
 
Reference:
大骆驼
Perl by example
http://tech.ccidnet.com/art/3539/20100817/2155949_1.html)
Perl中文手册 http://man.ddvip.com/web/perl/perl14.htm