Perl 之 use(), require(), do(), %INC and @INC
来源:
http://www.cnblogs.com/itech/archive/2013/03/12/2956185.html
转自:http://perl.apache.org/docs/general/perl_reference/perl_reference.html
use(), require(), do(), %INC and @INC Explained
The @INC array
@INC
is a special Perl variable which is the equivalent of the shell's PATH
variable. Whereas PATH
contains a list of directories to search for executables, @INC
contains a list of directories from which Perl modules and libraries can be loaded.
When you use(), require() or do() a filename or a module, Perl gets a list of directories from the @INC
variable and searches them for the file it was requested to load. If the file that you want to load is not located in one of the listed directories, you have to tell Perl where to find the file. You can either provide a path relative to one of the directories in @INC
, or you can provide the full path to the file.
The %INC hash
%INC
is another special Perl variable that is used to cache the names of the files and the modules that were successfully loaded and compiled by use(), require() or do() statements. Before attempting to load a file or a module with use() or require(), Perl checks whether it's already in the %INC
hash. If it's there, the loading and therefore the compilation are not performed at all. Otherwise the file is loaded into memory and an attempt is made to compile it. do() does unconditional loading--no lookup in the %INC
hash is made.
If the file is successfully loaded and compiled, a new key-value pair is added to %INC
. The key is the name of the file or module as it was passed to the one of the three functions we have just mentioned, and if it was found in any of the @INC
directories except "."
the value is the full path to it in the file system.
The following examples will make it easier to understand the logic.
First, let's see what are the contents of @INC
on my system:
% perl -e 'print join "\n", @INC'
/usr/lib/perl5/5.00503/i386-linux
/usr/lib/perl5/5.00503
/usr/lib/perl5/site_perl/5.005/i386-linux
/usr/lib/perl5/site_perl/5.005
.
Notice the .
(current directory) is the last directory in the list.
Now let's load the module strict.pm
and see the contents of %INC
: 打印%INC
% perl -e 'use strict; print map {"$_ => $INC{$_}\n"} keys %INC' strict.pm => /usr/lib/perl5/5.00503/strict.pm
Since strict.pm
was found in /usr/lib/perl5/5.00503/ directory and /usr/lib/perl5/5.00503/ is a part of @INC
, %INC
includes the full path as the value for the key strict.pm
.
Now let's create the simplest module in /tmp/test.pm
:
test.pm
-------
1;
It does nothing, but returns a true value when loaded. Now let's load it in different ways:
% cd /tmp
% perl -e 'use test; print map {"$_ => $INC{$_}\n"} keys %INC' test.pm => test.pm
Since the file was found relative to .
(the current directory), the relative path is inserted as the value. If we alter @INC
, by adding /tmp to the end:
% cd /tmp
% perl -e 'BEGIN{push @INC, "/tmp"} use test; \
print map {"$_ => $INC{$_}\n"} keys %INC' test.pm => test.pm
Here we still get the relative path, since the module was found first relative to "."
. The directory /tmp was placed after .
in the list. If we execute the same code from a different directory, the "."
directory won't match,
% cd /
% perl -e 'BEGIN{push @INC, "/tmp"} use test; \
print map {"$_ => $INC{$_}\n"} keys %INC' test.pm => /tmp/test.pm
so we get the full path. We can also prepend the path with unshift(), so it will be used for matching before "."
and therefore we will get the full path as well:
% cd /tmp
% perl -e 'BEGIN{unshift @INC, "/tmp"} use test; \
print map {"$_ => $INC{$_}\n"} keys %INC' test.pm => /tmp/test.pm
The code:
BEGIN{unshift @INC, "/tmp"}
can be replaced with the more elegant:
use lib "/tmp";
Which is almost equivalent to our BEGIN
block and is the recommended approach.
These approaches to modifying @INC
can be labor intensive, since if you want to move the script around in the file-system you have to modify the path. This can be painful, for example, when you move your scripts from development to a production server.
There is a module called FindBin
which solves this problem in the plain Perl world, but unfortunately up untill perl 5.9.1 it won't work under mod_perl, since it's a module and as any module it's loaded only once. So the first script using it will have all the settings correct, but the rest of the scripts will not if located in a different directory from the first. Perl 5.9.1 provides a new function FindBin::again
which will do the right thing. Also the CPAN module FindBin::Real
provides a working alternative working under mod_perl.
For the sake of completeness, I'll present the FindBin
module anyway.
If you use this module, you don't need to write a hard coded path. The following snippet does all the work for you (the file is /tmp/load.pl):
load.pl
-------
#!/usr/bin/perl use FindBin ();
use lib "$FindBin::Bin";
use test;
print "test.pm => $INC{'test.pm'}\n";
In the above example $FindBin::Bin
is equal to /tmp. If we move the script somewhere else... e.g. /tmp/new_dir in the code above $FindBin::Bin
equals /tmp/new_dir.
% /tmp/load.pl test.pm => /tmp/test.pm
This is just like use lib
except that no hard coded path is required.
You can use this workaround to make it work under mod_perl.
do 'FindBin.pm';
unshift @INC, "$FindBin::Bin";
require test;
#maybe test::import( ... ) here if need to import stuff
This has a slight overhead because it will load from disk and recompile the FindBin
module on each request. So it may not be worth it.
查看某个模块是在哪个lib路径下被登录的(一般是写在use 之后的某个要测试的地方)
print($INC{"Cwd.pm"}, "\n"); 如果有则输出对应文件所在的位置。如 C:/Perl/lib/Cwd.pm
print($INC{"File/Basename.pm"}, "\n"); 这边要找的是use File::Basename所使用的模块位置 如 C:/Perl/lib/File/Basename.pm
print($INC{"Basename.pm"}, "\n"); 如果还没登录、文件路径不对,则不输出任何东西
Modules, Libraries and Program Files
Before we proceed, let's define what we mean by module, library and program file.
- Libraries(这类可以归为一般perl和module中去。如果要用,可以作为.h来用)
These are files which contain Perl subroutines and other code.
When these are used to break up a large program into manageable chunks they don't generally include a package declaration; when they are used as subroutine libraries they often do have a package declaration.
如果真的作为一个module用,则Their last statement returns true, a simple
1;
statement ensures that.They can be named in any way desired, but generally their extension is .pl.
Examples:
config.pl
----------
# No package so defaults to main::
$dir = "/home/httpd/cgi-bin";
$cgi = "/cgi-bin";
1; mysubs.pl
----------
# No package so defaults to main::
sub print_header{
print "Content-type: text/plain\r\n\r\n";
}
1; web.pl
------------
package web ;
# Call like this: web::print_with_class('loud',"Don't shout!");
sub print_with_class{
my ( $class, $text ) = @_ ;
print qq{<span class="$class">$text</span>};
}
1; - Modules
A file which contains perl subroutines and other code.
It generally declares a package name at the beginning of it.
Modules are generally used either as function libraries (which .pl files are still but less commonly used for), or as object libraries where a module is used to define a class and its methods.
Its last statement returns true.
The naming convention requires it to have a .pm extension.
Example:
MyModule.pm
-----------
package My::Module;
$My::Module::VERSION = 0.01; sub new{ return bless {}, shift;}
END { print "Quitting\n"}
1; - Program Files
Many Perl programs exist as a single file. Under Linux and other Unix-like operating systems the file often has no suffix since the operating system can determine that it is a perl script from the first line (shebang line) or if it's Apache that executes the code, there is a variety of ways to tell how and when the file should be executed. Under Windows a suffix is normally used, for example
.pl
or.plx
.The program file will normally
require()
any libraries anduse()
any modules it requires for execution.It will contain Perl code but won't usually have any package names.
Its last statement may return anything or nothing.
require()
require() reads a file containing Perl code and compiles it. Before attempting to load the file it looks up the argument in %INC
to see whether it has already been loaded. If it has, require() just returns without doing a thing. Otherwise an attempt will be made to load and compile the file.
require() has to find the file it has to load. If the argument is a full path to the file, it just tries to read it. For example:
require "/home/httpd/perl/mylibs.pl";
If the path is relative, require() will attempt to search for the file in all the directories listed in @INC
. For example:
require "mylibs.pl";
If there is more than one occurrence of the file with the same name in the directories listed in @INC
the first occurrence will be used.
The file must return TRUE as the last statement to indicate successful execution of any initialization code. Since you never know what changes the file will go through in the future, you cannot be sure that the last statement will always return TRUE. That's why the suggestion is to put "1;
" at the end of file.
Although you should use the real filename for most files, if the file is a module, you may use the following convention instead:
require My::Module;
This is equal to:
require "My/Module.pm";
If require() fails to load the file, either because it couldn't find the file in question or the code failed to compile, or it didn't return TRUE, then the program would die(). To prevent this the require() statement can be enclosed into an eval() exception-handling block, as in this example:
require.pl
----------
#!/usr/bin/perl -w eval { require "/file/that/does/not/exists"};
if ($@) {
print "Failed to load, because : $@"
}
print "\nHello\n";
When we execute the program:
% ./require.pl Failed to load, because : Can't locate /file/that/does/not/exists in
@INC (@INC contains: /usr/lib/perl5/5.00503/i386-linux
/usr/lib/perl5/5.00503 /usr/lib/perl5/site_perl/5.005/i386-linux
/usr/lib/perl5/site_perl/5.005 .) at require.pl line 3. Hello
We see that the program didn't die(), because Hello was printed. This trick is useful when you want to check whether a user has some module installed, but if she hasn't it's not critical, perhaps the program can run without this module with reduced functionality.
If we remove the eval() part and try again:
require.pl
----------
#!/usr/bin/perl -w require "/file/that/does/not/exists";
print "\nHello\n"; % ./require1.pl Can't locate /file/that/does/not/exists in @INC (@INC contains:
/usr/lib/perl5/5.00503/i386-linux /usr/lib/perl5/5.00503
/usr/lib/perl5/site_perl/5.005/i386-linux
/usr/lib/perl5/site_perl/5.005 .) at require1.pl line 3.
The program just die()s in the last example, which is what you want in most cases.
For more information refer to the perlfunc manpage.
use()
use(), just like require(), loads and compiles files containing Perl code, but it works with modules only and is executed at compile time.
The only way to pass a module to load is by its module name and not its filename. If the module is located in MyCode.pm, the correct way to use() it is:
use MyCode
and not:
use "MyCode.pm"
use() translates the passed argument into a file name replacing ::
with the operating system's path separator (normally /
) and appending .pm at the end. So My::Module
becomes My/Module.pm.
use() is exactly equivalent to:
BEGIN { require Module; Module->import(LIST); }
Internally it calls require() to do the loading and compilation chores. When require() finishes its job, import() is called unless ()
is the second argument. The following pairs are equivalent:
use MyModule;
BEGIN {require MyModule; MyModule->import; } use MyModule qw(foo bar);
BEGIN {require MyModule; MyModule->import("foo","bar"); } use MyModule ();
BEGIN {require MyModule; }
The first pair exports the default tags. This happens if the module sets @EXPORT
to a list of tags to be exported by default. The module's manpage normally describes what tags are exported by default.
The second pair exports only the tags passed as arguments.
The third pair describes the case where the caller does not want any symbols to be imported.
import()
is not a builtin function, it's just an ordinary static method call into the "MyModule
" package to tell the module to import the list of features back into the current package. See the Exporter manpage for more information.
When you write your own modules, always remember that it's better to use @EXPORT_OK
instead of @EXPORT
, since the former doesn't export symbols unless it was asked to. Exports pollute the namespace of the module user. Also avoid short or common symbol names to reduce the risk of name clashes.
When functions and variables aren't exported you can still access them using their full names, like $My::Module::bar
or $My::Module::foo()
. By convention you can use a leading underscore on names to informally indicate that they are internal and not for public use.
There's a corresponding "no
" command that un-imports symbols imported by use
, i.e., it calls Module->unimport(LIST)
instead of import()
.
do()
While do() behaves almost identically to require(), it reloads the file unconditionally. It doesn't check %INC
to see whether the file was already loaded.
If do() cannot read the file, it returns undef
and sets $!
to report the error. If do() can read the file but cannot compile it, it returns undef
and puts an error message in $@
. If the file is successfully compiled, do() returns the value of the last expression evaluated.
Perl 之 use(), require(), do(), %INC and @INC的更多相关文章
- perl的USE和require
来源: http://www.cnblogs.com/itech/archive/2010/11/22/1884345.html 相同: 都可以用来引用module(.PM). 不同: 1) 区别在于 ...
- perl学习之:use & require
相同: 都可以用来引用module(.PM). 不同: 1) 区别在于USE是在当前默认的@INC里面去寻找,一旦模块不在@INC中的话,用USE是不可以引入的,但是require可以指定路径: 2) ...
- perl学习之:use and require
本文和大家重点学习一下Perl use和require用法对比,这两个函数都是一个意思,加载和引用Perl的模块,或者是子程序,区别在于Perl use是在当前默认的里面去寻找,一旦模块不在指定的区域 ...
- Installing perl and writing your first perl program in Ubuntu
Installing perl and writing your first perl program in Ubuntu Installing perl and writing your f ...
- perl 第十四章 Perl5的包和模块
第十四章 Perl5的包和模块 by flamephoenix 一.require函数 1.require函数和子程序库 2.用require指定Perl版本二.包 1.包的定义 2.在包间切 ...
- perl学习之:package and module
perl的包(package)和模块(PM) ==================================包package=========================== pac ...
- perl 打印简单的help文档
更多 PrintHelp.pm #!/usr/bin/perl package PrintHelp; require Exporter; use v5.26; use strict; use utf8 ...
- MySQL中文参考手册
1 MySQL 的一般信息 这是MySQL参考手册:它记载了MySQL版本3.23.7-alpha. MySQL 是一个快速.多线程.多用户和强壮的SQL数据库服务器. 对Unix和 OS/2 平台, ...
- 使用node.js + socket.io + redis实现基本的聊天室场景
在这篇文章Redis数据库及其基本操作中介绍了Redis及redis-cli的基本操作. 其中的publish-subscribe机制应用比较广泛, 那么接下来使用nodejs来实现该机制. 本文是对 ...
随机推荐
- 淘淘商城_day11_课堂笔记
今日大纲 发布前的准备 实施发布 一部分是由我来发布 一部分是由你们来发布 讲解分布式部署架构 测试 功能测试 压力测试 项目实战的准备以及分组 分组 抽取功能 讲解所需要开发的功能 项目部署上线流程 ...
- js常见的判断移动端或者pc端或者安卓和苹果浏览器的方法总结
1.js常见的判断移动端或者pc端或者安卓和苹果浏览器的方法总结 : http://www.haorooms.com/post/js_pc_iosandmobile 2.Js判断客户端是否为PC还是手 ...
- 《JS权威指南学习总结--7.8 数组方法》
内容要点: 一.join() Array.join()方法将数组中所有元素都转化为字符串并连接在一起,返回最后生产的字符串. 可以指定一个可选的字符串在生产的字符串中来分隔数组的各个元素.如果不指定分 ...
- 【LeetCode】434. Number of Segments in a String
Count the number of segments in a string, where a segment is defined to be a contiguous sequence of ...
- Struts2配置文件动态传参
两个Action动态传递参数: 1.从一个Action传递到另一个Action如果带有参数那么result中的type属性需要使用redirect 第一个Action代码如下: private Str ...
- 【转】Java线程与Linux内核线程的映射关系
Linux从内核2.6开始使用NPTL (Native POSIX Thread Library)支持,但这时线程本质上还轻量级进程. Java里的线程是由JVM来管理的,它如何对应到操作系统的线程是 ...
- 判定生死的心跳机制 --ESFramework 4.0 快速上手(07)
在Internet上采用TCP进行通信的系统,都会遇到一个令人头疼的问题,就是"掉线".而"TCP掉线"这个问题远比我们通常所能想象的要复杂的多 -- 网络拓扑 ...
- Chapter 15_3 使用环境
创建模块的基本方法的缺点在于,忘记使用local,很容易就污染全局空间. “函数环境”是一种有趣的技术,它能够解决上面的问题.就是让模块的主程序块独占一个环境. 这样不仅它的所有函数可以共享这个tab ...
- ubuntu下安装BeyondCompare比较工具
在ubuntu12.04下使用比较工具,这里参考了网上的一个方法来安装BeyondCompare3 首先,下载相关软件: 这里选择了BCompare: http://www.scootersoftwa ...
- crontab定时任务
使用cron服务,用 service crond status 查看 cron服务状态,如果没有启动则 service crond start启动它, cron服务是一个定时执行的服务,可以通过cro ...