【问题标题】:Is it possible to get access to a symbol table without disabling strict?是否可以在不禁用严格的情况下访问符号表?
【发布时间】:2020-03-03 02:31:43
【问题描述】:

在 Perl 中,以下代码非常常见。你甚至可以在constant.pm 之类的地方看到它。

my $symtab;
{
  no strict 'refs';                                                                                                                              
  $symtab = \%{$pkg . '::'};
}

如果我只是删除严格,我得到

在使用“严格引用”时不能使用字符串 (main::) 作为 HASH 引用

有没有可能在不关闭strict的情况下做到这一点?

【问题讨论】:

  • 嗯,你必须做到这一点没有严格。你的意思是我为什么要严格?因为我想我喜欢严格,我需要访问符号表,我只是想知道是否有一种不那么 hacky 的方法来做到这一点?
  • 在我看来,在一个小的词法范围内禁用strict 是完全正确的做法。它是为了阻止你做这些事情,所以明确禁用这部分严格政策是支持这一点的,并告诉代码的读者你知道你在做什么。
  • 您当然可以使用 XS 代码来实现。也许有一个基于B 的解决方案也可以在strict 下运行。

标签: perl strict


【解决方案1】:

如果您不需要构造存储名称,Strict 不会阻止访问:

use strict;
use warnings;
$Foo::Bar::baz = 42;
my $symtab = \%Foo::Bar::;
print "${$symtab->{baz}}\n";

您也可以通过 stash 层次结构访问它而不会违反严格(它一直向下):

use strict;
use warnings;
$Foo::Bar::baz = 42;
my $main_stash = \%::;
my $Foo_stash = $main_stash->{'Foo::'};
my $FooBar_stash = $Foo_stash->{'Bar::'};
print "${$FooBar_stash->{baz}}\n";

Package::Stash 提供了一种访问存储的编程方式。

use strict;
use warnings;
use Package::Stash;
$Foo::Bar::baz = 42;
my $package = 'Foo::Bar';
my $stash = Package::Stash->new($package);
print "${$stash->namespace->{baz}}\n"; # dereferencing the glob to access the scalar slot
print "${$stash->get_symbol('$baz')}\n"; # retrieving the scalar slot of the glob directly

警告购买者:仅仅因为严格的变量不阻止存储层次结构访问并不意味着这不是hacky(并且抵抗编译时优化),并且在大多数情况下只是关闭严格的'refs'并构造符号名称是首选。

【讨论】:

  • 但是在这里要清楚,给定包名,访问该包的符号表需要“构造”它(即附加::),这违反了严格模式?
  • 不一定;你也可以在 parent stash 中找到它,但它有点复杂;将更新答案。
【解决方案2】:

不关闭strict 是不可能的。但是有一些方法可以隐藏这种复杂性。有几个模块可以让您在不关闭 strict 的情况下执行此操作 - Symbol(包含在标准发行版中)、Symbol::GetTie::Symbol 是三个示例。

【讨论】:

    【解决方案3】:

    通过找到一种与 strict on 相关的方法来掩盖您正在做的事情并非严格安全的事实只会愚弄您自己和您的读者。这是个坏主意。


    首先,这不是很常见。它由一些低级模块完成。普通的 Perl 程序员永远不会直接操作符号表。

    是的,可以在不禁用strict 的情况下执行此操作。符号表可通过%:: 访问,因此您可以解析包并以这种方式导航符号表。例如,\%{'Foo::Bar::'} 变为 \%{ $::{"Foo::"}{"Bar::"} },尽管这以包的存在为前提。您还可以生成 Perl 代码并使用 eval

    但是,没有理由这样做。一个人专门打开 strict 以防止自己不小心这样做。掩盖你正在做的事情不是严格安全的事实只会愚弄你自己和你的读者。这是个坏主意。应该努力编写自我记录的代码,没有什么比no strict 'refs'; 更能说明“这是一个棘手、危险的代码”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-26
      • 2021-08-05
      • 1970-01-01
      • 1970-01-01
      • 2012-07-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多