我有一个php-ini文件,我需要用Config::IniFiles
解析和阅读。在这个ini文件中是从其他部分继承其设置的部分。结构如下所示:
[section1]
...
...
[section2:section1]
...
...
[section3:section2]
...
...
等等。
现在,如果我想从section3
读取键的值,则该对象返回undef,因为它只知道section3:section2
部分。正如您可能已经预料到的那样,这不是继承所需的行为。在我的情况下,我希望该对象首先尝试从section3
读取值,如果它在那里找不到,请尝试section2
然后section1
。有没有办法用这个模块来实现这个目标,还是我必须编写一个包装模块并自己实现这个功能?
答案 0 :(得分:2)
我找不到实现配置继承的Perl模块。
但是编写一个能够实现继承的简单过滤器并不复杂。给定一个HoH,如果我们将配置中的每个条目看作一个delta,我们就可以解决下面的继承:
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;
}
测试:
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';
正如您所看到的,这为:
- 运算符提供了正确的关联性(从右到左组合)。
如果你想要深度优先分辨率,即:
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
函数,并将其更改为
my $resolve; $resolve = sub {
my $child = shift;
return $child, map { $resolve->($_) } $get_parents->($child);
};
这是最小的变化,但当然只需保留每个父项的最左边一个,就可以提高效率:
use List::MoreUtils 'uniq';
my $resolve; $resolve = sub {
my $child = shift;
return uniq $child, map { $resolve->($_) } $get_parents->($child);
};
如果用于输入的数据结构可以记住部分的顺序,那么这种深度优先解决方案将变得更加容易。但是,哈希是无序的。