我想创建一个带有数组,键字符串和值字符串的映射函数。这两个字符串包含我想要针对数组中的每个元素进行评估的PHP代码。
这两个调用的返回值应该用作将返回的关联数组中的键和值。
E.g。
$assoc_list = my_mapper_function($list_of_people, 'id', 'full_name()');
假设列表包含两个人,Alice和Bob,其id为4和5 - 返回值应该是这样的:
[
'4' => 'Alice Foo',
'5' => 'Bob Bar'
]
关于如何做到这一点的任何想法?
对于属性来说它很简单,因为你可以使用括号表示法,但我希望它也能用于(链式)函数调用。
以下是我想到的代码,遗憾的是它仅适用于属性:
public static function assoc_mapper($array, $key, $value) {
$results = array();
foreach ($array as $element) {
$results[$element[$key]] = $element[$value];
}
return $results;
}
答案 0 :(得分:0)
到目前为止,我能够做到的唯一方法是使用官方文档警告的eval
。但是,由于我没有使用用户输入,因此不存在安全风险。
public static function assoc_mapper($array, $key_expression, $value_expression) {
$results = array();
foreach ($array as $element) {
$key = eval("return \$element->$key_expression;");
$value = eval("return \$element->$value_expression;");
$results[$key] = $value;
}
return $results;
}
如果有人有一个更加狡猾的想法仍然保持方法通话时间短,我会很乐意接受答案。
答案 1 :(得分:0)
未经测试,很快被黑了,但我希望你明白这个想法。不使用文字foo()->bar()
表示法,而是使用简化的foo.bar
表示法,您可以通过各种方式自行处理。
function getPropertyFromString($obj, $string) {
if (is_array($obj) && array_key_exists($string, $obj)) {
return $obj[$string];
} else if (is_object($obj)) {
if (isset($obj->$string)) {
return $obj->$string;
} else if (method_exists($obj, $string)) {
return call_user_func(array($obj, $string));
} else if (method_exists($obj, 'get' . ucfirst($string))) {
return call_user_func(array($obj, 'get' . ucfirst($string)));
}
}
return null;
}
function getValue($obj, $getter) {
if (is_string($getter)) {
return array_reduce(explode('.', $getter), 'getPropertyFromString', $obj);
} else if (is_callable($getter)) {
return call_user_func($getter, $obj);
}
throw new InvalidArgumentException('Invalid getter');
}
function mapper(array $array, $keyGetter, $valueGetter) {
$result = array();
foreach ($array as $value) {
$result[getValue($value, $keyGetter)] = getValue($value, $valueGetter);
}
return $result;
}
示例:
mapper($array, 'id', 'name'); // simple properties
mapper($array, 'foo.bar', 'baz'); // nested properties
// super complex values
mapper($array, 'id', function ($obj) { return strtoupper($obj->foo(42)->bar()->baz); });