2

我找到了一些解决我一直遇到的排序问题的方法,但是代码在 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按其他数组排序多维数组

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

来自PHP - 按另一个数组对多维数组进行排序

更新:问题之一是我不确定如何使用变量 $a、$b 和 $v。所以我不确定如何创建普通函数,从而绕过匿名函数。

4

4 回答 4

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);

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

于 2012-11-27T17:37:17.450 回答
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 已过时且不受支持。您应该尽快迁移出去。

于 2012-11-27T17:36:52.903 回答
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

于 2012-11-27T17:40:31.460 回答
0

您还可以将其重写为 5.3 之前的匿名函数,例如 la 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);

The more general pre-5.3 solution, though, is to use an object and method as the closure, as in hakra's answer.

于 2012-11-29T01:35:31.017 回答