PHP修改代码以避免匿名函数

时间:2012-11-27 17:26:55

标签: php anonymous-function

我找到了一些我一直在使用的排序问题的解决方案,但代码在PHP中使用了匿名函数。我使用的是5.2.17版本,我认为不支持匿名功能。

我如何更改以下代码块,以便在PHP 5.2.17中使用它们

$keys = array_flip($order);

usort($items, function($a, $b) use($keys)
{
    return $keys[$a['id']] - $keys[$b['id']];
});

来自PHP sort multidimensional array by other array

$sorted = array_map(function($v) use ($data) {
    return $data[$v - 1];
}, $order);

来自PHP - Sort multi-dimensional array by another array

更新: 其中一个问题是我不确定如何使用变量$ a,$ b和$ v。所以我不确定如何创建正常的函数,从而绕过了anon函数。

4 个答案:

答案 0 :(得分:3)

两个匿名函数都使用use子句将变量传递到本地范围。

您可以使用对象方法实现相同的目标,其中对象将这些变量作为属性。

在对象方法中,您可以访问这些。

$sorted = array_map(function($v) use ($data) {
    return $data[$v - 1];
}, $order);

示例性映射对象则可能如下所示:

class MapObj
{
    private $data;
    public function __construct($data) {
        $this->data = $data;
    }

    public function callback($v) {
        return $this->data[$v - 1];
    }
}

正如您所看到的,它具有相同的功能,但只是用PHP 5.2语法编写。

它的用法:

$map = new MapObj($data);
$callback = array($map, 'callback');
$sorted = array_map($callback, $order);

这就是它的工作原理。对象方法的回调总是以array的形式写成,有两个成员,第一个是对象实例,第二个是对象方法的名称。

当然你可以将映射函数扩展到映射对象中,所以它更直接:

class MapObj
{
    ...

    public function map(array $order) {
        $callback = array($this, 'callback');
        return array_map($callback, $order);
    }
}

新用法:

$map = new MapObj($data);
$sorted = $map->map($order);

正如您所看到的,这可能会使用法更直接。我必须承认,我的方法命名在这里并不是很精彩,所以我给你的改进留下了一些空间。

另一个好处是,您可以将回调方法的可见性设为私有。


将数据作为映射函数的参数传递给回调的情况。那是因为你写道你已经有了一个你想要使用的类,但是你无法触及构造函数。所以给出的例子有点短。

这是另一个不使用构造函数的示例,我删除了它:

class MyObj
{
    private $data;

    private function callback($v) {
        return $this->data[$v - 1];
    }

    public function map($order, $data) {
        $callback = array($this, 'callback');
        $this->data = $data;
        return array_map($callback, $order);
    }
}

正如您所看到的,不再需要构造函数来传递$data,而是将其作为附加参数传递给map()方法。用法:

$myObj = new MyObj(....); // somewhere.

// later on:

$myObj->map($order, $data);

// could be also:

$this->map($order, $data);

如您所见,您如何设置私有成员变量取决于您。做适合自己的工作。

答案 1 :(得分:0)

这里有一个闭包而不是$data - 如果没有匿名函数,就不可能100%重写它。这是最接近的近似值:

function _array_sort_callback($a, $b) {
    global $_array_sort_callback__keys;
    return $_array_sort_callback__keys[$a['id']] - $_array_sort_callback__keys[$b['id']];
}

... {
    $keys = array_flip($order);
    global $_array_sort_callback__keys;
    $_array_sort_callback__keys = $keys;
    usort($items, "_array_sort_callback");
}

请注意,我已经为全局名称添加了前缀,以避免发生冲突。功能名称和全局名称在您的应用程序中都必须是唯一的。

另外,请记住PHP 5.2.17已过时且不受支持。你应该尽快迁移它。

答案 2 :(得分:0)

如果你想模仿一个闭包,你在特定时间快照变量,你可以使用一个简单的基类作为值的容器,然后只需定义子类来实现比较逻辑。

未测试

// base class exists purely to capture the value of some variables at instantiation time
// kinda like a closure
class VarCapture {
    protected $vars;
    function __construct($vars) {
        $this->vars = $vars;
    }
}
class ItemComparer extends VarCapture {
    function compare($a, $b) {
       $keys = $this->vars['keys'];
       return $keys[$a['id']] - $keys[$b['id']];
    }
}

class PluckMapper extends VarCapture {
    function pluck($v) {
        $data = $this->vars['data'];
        return $data[$v - 1];
    }
}
$keys = array_flip($order);
$ic = new ItemComparer(compact('keys'));
$callable = array($ic, 'compare');
usort($items, $callable);

$pm = new PluckMapper(compact('data'));
$callable = array($mp, 'pluck');
$sorted = array_map($callable, $order);

请注意,我使用了php的回调伪类型 http://php.net/manual/en/language.types.callable.php

答案 3 :(得分:0)

您也可以将其重新编写为5.3之前的匿名函数,即create_function()。虽然create_function()函数通常不作为闭包,但您可以使用一些技巧(不使用全局变量)使它们在某些有限的情况下用作闭包。您将关闭的变量直接编码到函数的源中。限制是数据只是单向进入;封闭变量只能是“简单”数据类型,如数字,字符串和数组;使用create_function创建的函数永远不会被释放,泄漏内存;再加上效率不高。但我认为这对你的例子来说已经足够了(假设你只使用数组和字符串等)。

$keys = array_flip($order);

usort($items, create_function('$a,$b', '$keys = '.var_export($keys,true).';
    return $keys[$a["id"]] - $keys[$b["id"]];
'));

$sorted = array_map(create_function('$v', '$data = '.var_export($data,true).';
    return $data[$v - 1];
'), $order);

更一般的5.3之前的解决方案是使用对象和方法作为闭包,就像hakra的回答一样。