创建一个php映射器函数


Creating a php mapper function

我想创建一个映射函数,它接受一个数组、一个键字符串和一个值字符串。这两个字符串包含PHP代码,我希望对数组中的每个元素进行评估。

这两个调用的返回值应该用作将要返回的关联数组中的键和值。

例如

$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;
}

到目前为止,我能够做到这一点的唯一方法是使用官方文档警告不要使用的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;
}

如果有人有一个更巧妙的想法,仍然可以缩短方法调用,我很乐意接受这个答案。

未经测试,很快就被破解了,但我希望你能明白。与其使用字面上的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); });