创建一个php mapper函数

时间:2013-12-07 22:29:47

标签: php metaprogramming

我想创建一个带有数组,键字符串和值字符串的映射函数。这两个字符串包含我想要针对数组中的每个元素进行评估的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;
}

2 个答案:

答案 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); });