首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >节-使用Config的继承::IniFiles

节-使用Config的继承::IniFiles
EN

Stack Overflow用户
提问于 2013-09-12 05:50:35
回答 1查看 224关注 0票数 0

我有一个php-ini文件,需要用Config::IniFiles解析和读取。在这个ini文件中是从其他部分继承它们的设置的部分。结构如下:

代码语言:javascript
复制
[section1]
...
...
[section2:section1]
...
...
[section3:section2]
...
...

诸若此类。

现在,如果我想从section3读取键的值,对象返回undef,因为它只知道section3:section2节。正如您可能已经预料到的那样,这不是继承的理想行为。在我的例子中,我希望对象首先尝试从section3读取值,如果它在那里找不到它,尝试section2,然后尝试section1。有什么方法可以用这个模块来实现这个功能吗?还是我必须自己编写一个包装模块并实现这个功能呢?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-09-12 08:47:43

我找不到实现配置继承的Perl模块。

但是,编写一个简单的过滤器来计算继承并没有那么复杂。给定一个HoH,我们可以像下面这样解析继承,如果我们将配置中的每个条目看作是一个增量:

代码语言:javascript
复制
use Algorithm::C3;  # must be installed from CPAN

sub resolve_inheritance {
  my $input = shift;
  my %output;

  # hash of arrays where the arrays contain all parents
  my %child_parent_relations =
    map { my ($c, @p) = split /\s*:\s*/; $c => [\@p, $input->{$_}] } keys %$input;
  my $get_parents = sub { @{ $child_parent_relations{shift()}[0] } };
  my $get_data    = sub {    $child_parent_relations{shift()}[1] };

  # prepare stuff for C3 resolution
  my $resolution_cache = {};
  my $resolve = sub {
    my $child = shift;
    Algorithm::C3::merge($child, $get_parents, $resolution_cache);
  };

  # now we go through all childs, and build temporary hashes from the C3 linearization.
  for my $child (keys %child_parent_relations) {
    my @linearization = $resolve->($child);
    my %temp;
    for my $delta_name (reverse @linearization) {
      my $delta = $get_data->($delta_name);
      @temp{keys %$delta} = values %$delta;
    }
    # save the data in the output:
    $output{$child} = \%temp;
  }

  return \%output;
}

测试:

代码语言:javascript
复制
my $input = {
  's1'       => { A => 1 },
  's2:s1'    => { A => 2, B => 2 },
  's3:s1'    => { B => 3, C => 3 },
  's4:s3:s2' => { }
};
my $expected = {
  's1' => { A => 1 },
  's2' => { A => 2, B => 2 },
  's3' => { A => 1, B => 3, C => 3 },
  's4' => { A => 2, B => 3, C => 3 },
};
use Test::More tests => 1;
is_deeply resolve_inheritance($input), $expected, 'C3 resolution';

如您所见,这给了:-operator右结合(从右到左组合)。

如果您想要深度第一分辨率,即:

代码语言:javascript
复制
my $expected = {
  's1' => { A => 1 },
  's2' => { A => 2, B => 2 },
  's3' => { A => 1, B => 3, C => 3 },
  's4' => { A => 1, B => 3, C => 3 },  # s3 completely overwrites s2
};

那你就得到了不同的结果。这可以通过首先继承每个父级,然后仅结合直接父级,而不是整个层次结构来完成。在单次遗传的情况下,深度优先线性化和C3分辨率的结果是等价的.

为了支持深度优先分辨率,我们在上面的代码中交换了$resolve函数,并将它更改为

代码语言:javascript
复制
my $resolve; $resolve = sub {
  my $child = shift;
  return $child, map { $resolve->($_) } $get_parents->($child);
};

这是最小的更改,但当然可以通过只保留每个家长最左边的位置来提高效率:

代码语言:javascript
复制
use List::MoreUtils 'uniq';

my $resolve; $resolve = sub {
  my $child = shift;
  return uniq $child, map { $resolve->($_) } $get_parents->($child);
};

如果用于输入的数据结构能够记住节的顺序,那么这种深度优先解决方案将变得更加容易。然而,散列是无序的。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18756300

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档