防止将字符串解释为文件句柄

时间:2014-04-26 14:18:44

标签: perl filehandle method-call

Perl的功能是将名为文件句柄的字符串带到 文件句柄:

# let this be some nice class I wrote
package Input {
    sub awesome { ... }
}

因此,当我们执行Input->awesome或额外注意:'Input'->awesome时,将调用该方法。除非:

# now somewhere far, far away, in package main, somebody does this:
open Input, "<&", \*STDIN or die $!;  # normally we'd open to a file

此代码甚至不必执行,但只有解析器才能看到,以便Perl从现在开始将字符串'Input'解释为文件句柄。因此,方法调用'Input'->awesome将会死亡,因为表示文件句柄的对象没有很棒的方法。

由于我只控制着我的班级而不是其他代码,我不能简单地决定只在任何地方使用词汇文件句柄。

有什么方法可以强制Input->awesome永远是Input包上的方法调用,但永远不是文件句柄(至少在我控制的范围内)?我认为不应该有任何名称冲突,因为Input包实际上是%Input::存储。

重现问题的完整代码(另请参阅此ideone):

use strict;
use warnings;
use feature 'say';

say "This is perl $^V";

package Input {
    sub awesome {
        say "yay, this works";
    }
}

# this works
'Input'->awesome;

# the "open" is parsed, but not actually executed
eval <<'END';
    sub red_herring {
        open Input, "<&", \*STDIN or die $!;
    }
END
say "eval failed: $@" if $@;

# this will die
eval {
    'Input'->awesome;
};
say "Caught: $@" if $@;

示例输出:

This is perl v5.16.2
yay, this works
Caught: Can't locate object method "awesome" via package "IO::File" at prog.pl line 27.

2 个答案:

答案 0 :(得分:5)

对两个不同的东西(使用过的类和文件句柄)使用相同的标识符引发问题。如果您的类是在使用文件句柄的代码中使用的其他类中使用的,则不会出现错误:

My1.pm

package My1;

use warnings;
use strict;

sub new { bless [], shift }
sub awesome { 'My1'->new }

__PACKAGE__

My2.pm

package My2;

use warnings;
use strict;
use parent 'My1';

sub try {
    my $self = shift;
    return ('My1'->awesome, $self->awesome);
}

__PACKAGE__

script.pl

#!/usr/bin/perl
use warnings;
use strict;

use My2;
open My1, '<&', *STDIN;
my $o = 'My2'->new;
print $o->awesome, $o->try;

答案 1 :(得分:3)

使用裸字Input作为文件句柄是违反命名约定,只有FILEHANDLE的大写裸字和{{1}的大写/ CamelCased裸字} es和Class s。

此外,很久以前就已经引入并鼓励了lexcial Package

因此,使用您的类的程序员显然行为不端,并且由于命名空间是按定义全局的,因此Perl很难解决这个问题(支持chorobas关于乞求问题的声明)。

某些命名约定对所有(动态)语言都至关重要。

感谢有趣的问题,我第一次在SO中看到一个Perl问题,我更愿意看到perlmonks! :)

更新:此处的讨论已经深化:http://www.perlmonks.org/?node_id=1083985