没有详细介绍,这是我正在开发的模板系统,专门用于支持模板过滤器和函数中的命名参数。
我将尽力使用我的escapeHtml过滤器来解决问题,在本机PHP中基本上是htmlspecialchars
。
考虑一下,我有这个映射数组(这会根据被激活的函数或过滤器而改变)
$mapping = 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
)
);
为了解释这一点,第一级密钥(如flags
)是输入名称,type
是支持的输入类型(这对此问题并不重要)。如果输入中没有提供,default
只是默认值。现在我正在开发的代码允许我必须映射到此数组的一些输入,输入可以索引(数字)或使用与上面的输入名称匹配的键。映射数组的索引输入的顺序正确或预期。
所以输入的一些例子,
$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 Repo就在这里:
https://github.com/ArtisiticPhoenix/Jet/
那就是说,我在自述文件和维基中添加了很多东西。这里的这一点对于这个问题并不重要,但应提供一些内容。在我的模板系统中,过滤器以这种方式在模板源中调用。
{ $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 );
感觉就像有更好的方法来做那件事。
更新2:我应该提到输入可能不包含上面的全部项目,因为在我的模板示例中它可能只是第一个参数。在这种情况下,我必须使用默认值。
更新3:感谢@darp的帮助,稍微修改一下就是我的最终代码。
echo '<pre>';
$mapping = 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(
0 => 'test', //string
'encoding' => 'ISO-8859-1',
'double_encode' => false,
1 => 3, //flags
);*/
/* //error: missing required param[ string ]
$input = array(
'encoding' => 'ISO-8859-1',
'double_encode' => false,
'flags' => 3,
);*/
/*
$input = array( //missing optional flags
0 => 'test', //string
'encoding' => 'ISO-8859-1',
'double_encode' => false,
);
*/
$namedParams = array_intersect_key($input, $mapping);
$numberedParams = array_diff_key($input, $mapping);
$unmappedKeys = array_keys(array_diff_key($mapping, $input));
$mappedParams = array();
foreach ( $unmappedKeys as $index => $unmapped ){
if( isset( $numberedParams[ $index ] ) ){
$mappedParams[ $unmapped ] = $numberedParams[ $index ];
}else{
if( !isset( $mapping[ $unmapped ]['default'] ) ){
die( "error:missing required param[ {$unmapped} ]on ".__LINE__);
}else{
$mappedParams[ $unmapped ] = $mapping[ $unmapped ]['default'];
}
}
}
$output = array_merge($namedParams, $mappedParams);
var_export($output);
第一种情况下的输出:
array (
'encoding' => 'ISO-8859-1',
'double_encode' => false,
'string' => 'test',
'flags' => 3,
)
在第二部分,我得到了一个错误,因为我错过了一个必需的值:
在第三个:
array (
'encoding' => 'ISO-8859-1',
'double_encode' => false,
'string' => 'test',
'flags' => 11,
)
如果有额外的东西,他们现在只是被忽略了,我应该检查一下,但这并不是什么大不了的事。我只是想避免很多框架都有的魔术黑盒子。我可以添加的唯一另一件事是将它们排序为正确的顺序,但我不确定是否还需要,这取决于我如何实现调用函数等。
无论如何,谢谢,
答案 0 :(得分:2)
没有测试过,但这应该接近你的想法。
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))
)
)
答案 1 :(得分:1)
这会处理映射,处理缺少的参数,应用缺省值或缺省值:
// 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
);
var_export($output)
:
array (
'string' => 'hello',
'flags' => 3,
'encoding' => 'ISO-8859-1',
'double_encode' => false,
)