Php 使用映射数组与带有部分键的数组合并关联数组(支持命名参数)
这是我正在开发的一个模板系统,专门用于支持我的模板过滤器和函数中的命名参数 我将使用我的escapeHtml过滤器(基本上是本机PHP中的Php 使用映射数组与带有部分键的数组合并关联数组(支持命名参数),php,arrays,Php,Arrays,这是我正在开发的一个模板系统,专门用于支持我的模板过滤器和函数中的命名参数 我将使用我的escapeHtml过滤器(基本上是本机PHP中的htmlspecialchars)尽我所能直截了当地解释问题 考虑一下,我有这个映射数组(这将根据调用的函数或过滤器而改变) 为了解释这一点,第一级键(如标志是输入名称,类型是支持的输入类型(这对这个问题不重要)。默认值只是在输入中未提供任何值时使用的默认值。现在,我正在开发的代码允许一些我必须映射到这个数组的输入,输入可以被索引(数字),或者使用与上面输入名
htmlspecialchars
)尽我所能直截了当地解释问题
考虑一下,我有这个映射数组(这将根据调用的函数或过滤器而改变)
为了解释这一点,第一级键(如标志
是输入名称,类型
是支持的输入类型(这对这个问题不重要)。默认值
只是在输入中未提供任何值时使用的默认值。现在,我正在开发的代码允许一些我必须映射到这个数组的输入,输入可以被索引(数字),或者使用与上面输入名称匹配的键。映射数组的索引输入顺序正确或符合预期
所以一些输入的例子
$input = array(
'string' => 'hello',
0 => 'ISO-8859-1',
1 => false,
'flags' => 3
);
现在我需要将它与映射数组协调,这样输出就是
$output = array(
'string' => 'hello',
'flags' => 3
'encoding' => 'ISO-8859-1',
'double_encode' => false,
);
因此,如果您了解到目前为止,我需要带有键的项来匹配映射数组,并按照它们出现的顺序添加任何剩余元素(数字索引)。有一些错误检查涉及,但我并不过分担心这一点在目前
我确实做到了这一点,但它花费了我大约70行代码和3个循环,因此如果你能克服这一点,作为额外的奖励,你可以在项目源代码中获得学分:)。我还没有添加任何代码(目前非常不稳定),但Git回购协议如下:
也就是说,我在自述和维基上添加了很多东西。下面这一点对问题并不重要,但应该提供一些内容。在我的模板系统中,过滤器是以这种方式在模板源中调用的
{ $variable|escapeHtml } //no params
{ $variable|escapeHtml( ) } //no params
{ $variable|escapeHtml( 3, 'ISO-8859-1', false) } //indexed params
{ $variable|escapeHtml( flags=3, double_encode=true, encoding='ISO-8859-1') } //intended support for named params
{ $variable|escapeHtml( 'ISO-8859-1', false, flags = 3) } //support for mixed params as in the example
在上述过滤器的情况下,第一个输入是变量$variable
的值,现在这将最终由我的模板系统编译成一个PHP类,看起来像这样
$output .= $this->isPrintable(
$this->_executeCallable( [
400,/* Token::T_FILTER */
'escapehtml',/* TagType */
['string'=>$this->get('variable'), 'flags'=>3, 'encoding'=>'ISO-8859-1', 'double_encode'=>true ]
] ),
'for variable[ T_VARIABLE_TAG::$variable ] on Line[ 2 ] In Template[ test.tpl ]'
);
不用说,我希望能用少于3个循环和70多行代码得到一个答案
谢谢
编辑::这大约是我现在所拥有的,当输入比混合类型更简单或基本上与地图数字索引匹配时,这是为了节省一些时间。此外,我在这里检查缺少必需参数时出错,即输入中没有的参数在映射数组中没有默认值
echo '<pre>';
$map = array(
'string' => array(
'type' => 'string'
),
'flags' => array(
'type' => 'integer',
'default' => 11
),
'encoding' => array(
'type' => 'string',
'default' => 'UTF-8'
),
'double_encode' => array(
'type' => 'boolean',
'default' => true
)
);
$input = array(
'string' => 'hello',
0 => 'ISO-8859-1',
1 => false,
'flags' => 3
);
/* //simple indexed input
$input = array(
'hello',
3,
'ISO-8859-1',
false
);
*/
$isNumeric = true;
foreach ( $input as $k => $v){
if(!is_numeric($k)){
$isNumeric = false;
}
}
if( !$isNumeric || count( $map ) != count( $input )){
$numeric = array();
$assoc = array();
//split input into associative and indexed keys
foreach ( $input as $k => $v){
if(!is_numeric($k)){
$assoc[$k] = $v;
}else{
$numeric[] = $v;
}
}
//setup a dummy array based off the map keys
$output = array_fill_keys( array_keys( $map ), '_UNSET_');
foreach( $output as $key => &$value ){
if( isset( $assoc[ $key ] ) ){
$value = $assoc[ $key ];
unset( $assoc[$key] );
}else if( count( $numeric ) > 0 ){
$value = array_shift( $numeric );
}else{
if( isset( $map[ $key ][ 'default' ]) ){
$value = $map[ $key ][ 'default' ];
}else{
//throw error for missing required param
die( "missing required param $key on ".__LINE__);
}
}
}
if( count( $assoc ) > 0 ){
var_export( $assoc );
die( "unused inputs on ".__LINE__);
}
if( count( $numeric ) > 0 ){
var_export( $numeric );
die( "unused inputs on ".__LINE__);
}
}else{
$output = array_combine(array_keys( $map ), $input);
}
var_export( $output );
array (
'encoding' => 'ISO-8859-1',
'double_encode' => false,
'string' => 'test',
'flags' => 3,
)
在第二个示例中,我得到了一个错误,因为我缺少一个必需的值:
在第三种情况下:
array (
'string' => 'hello',
'flags' => 3,
'encoding' => 'ISO-8859-1',
'double_encode' => false,
)
如果有额外的,他们只是忽略了目前,我应该检查他们,但这不是什么大不了的事。我只是想避免很多框架都有的那个神奇的黑匣子。我唯一可以添加的另一件事是将它们按正确的顺序排序,但我不确定是否需要,这取决于我如何实现调用函数等
无论如何,谢谢,这会处理映射,处理缺少的参数,在缺少参数或其值为空时应用默认值:
array_merge(
array_replace(
array_intersect_key($mapping, $input),
array_intersect_key($input, $mapping)
),
array_combine(
array_keys(array_diff_key($mapping, $input)),
array_values(array_diff_key($input, $mapping))
)
)
var\u导出($output)
:
还没有测试过,但我认为这应该接近你想要的
我觉得你应该分享这3个循环和70多行代码…我会给我几分钟的时间来解决一些依赖性。实际上,我必须在数组_组合之前进行错误检查,我喜欢这个答案,因为我想用类似的方式来做,只是我无法理解。实际上这很好,我已经做了所需的更改,以检查是否缺少具有默认值的参数。有了这个,它比我原来的小不了多少。我可能需要做一些基准测试,看看哪一个更快,尽管这可能会帮助我删除原始阵列的一些部分。谢谢,唯一真正的问题是,如果两个阵列的长度不相同,array_combine将发出警告,因此我可以使用到那里的所有内容。我也不需要包含默认值,我只需要确保没有默认值的没有丢失。我可以修改映射,默认情况下我使用反射来生成它。@derp,很抱歉我错过了这一部分,但如果有额外的映射,它也可以走另一条路,我想我可以将所有这些合并到一个简单的循环中,而不是数组合并&数组合并&数组行走部分,毫无疑问这是一个棘手的部分,不过前面的第一部分很好。这是可行的,但是对于我的用例来说,它太精简了,我必须做一些变化和错误检查,并且没有办法将它们挂接到中。DAPOR-声明、分配、处理、输出、返回。声明并分配数组,然后在分配后使用array_walk或其他数组转换来验证数据。
array (
'encoding' => 'ISO-8859-1',
'double_encode' => false,
'string' => 'test',
'flags' => 11,
)
// Get the named parameters from the input array.
$namedParams = array_intersect_key($input, $mapping);
// Get the mapping keys for those missing from input.
$unmappedKeys = array_keys(array_diff_key($mapping, $input));
// Get the unnamed parameters from the input.
// Pad the array with null placeholders for those missing.
$numberedParams = array_pad(
array_diff_key($input, $mapping),
count($unmappedKeys),
null);
// Map keys to the unnamed parameters.
$mappedParams = array_combine($unmappedKeys, $numberedParams);
// Merge.
$output = array_merge($namedParams, $mappedParams);
// Apply defaults from the $mapping array to parameters with null values.
array_walk(
$output,
function (&$v, $k, $m) {
$v = is_null($v) ? $m[$k]['default'] : $v;
},
$mapping
);
array (
'string' => 'hello',
'flags' => 3,
'encoding' => 'ISO-8859-1',
'double_encode' => false,
)
array_merge(
array_replace(
array_intersect_key($mapping, $input),
array_intersect_key($input, $mapping)
),
array_combine(
array_keys(array_diff_key($mapping, $input)),
array_values(array_diff_key($input, $mapping))
)
)