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

PHP修改代码以避免匿名函数,php,anonymous-function,Php,Anonymous Function,我已经找到了一些解决排序问题的方法,但是代码在PHP中使用了匿名函数。我使用的是5.2.17版,我相信匿名函数不受支持 如何更改以下代码块,以便在PHP5.2.17中使用它们 $keys = array_flip($order); usort($items, function($a, $b) use($keys) { return $keys[$a['id']] - $keys[$b['id']]; }); 从 及 从 更新: 问题之一是我不确定变量$a、$b和$v是如何使用的。因此

我已经找到了一些解决排序问题的方法,但是代码在PHP中使用了匿名函数。我使用的是5.2.17版,我相信匿名函数不受支持

如何更改以下代码块,以便在PHP5.2.17中使用它们

$keys = array_flip($order);

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

更新: 问题之一是我不确定变量$a、$b和$v是如何使用的。因此,我不确定如何创建正常函数,从而绕过anon函数。

这里的闭包是
$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");
}
请注意,我在全局文件的名称前加了前缀,以避免冲突。函数名和全局名在应用程序中都必须是唯一的


另外,请记住,PHP5.2.17已经过时且不受支持。您应该尽快从它迁移出去。

这两个匿名函数都使用
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];
    }
}
正如您所见,它具有相同的功能,但只是用PHP5.2语法编写的

它的用法是:

$map = new MapObj($data);
$callback = array($map, 'callback');
$sorted = array_map($callback, $order);
这就是它的工作原理。对象方法的回调总是以包含两个成员的
数组的形式编写,第一个是对象实例,第二个是对象方法的名称

当然,您可以扩展此功能,将映射函数放入映射对象中,这样更直观:

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

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

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

未经测试

// 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的回调psuedo类型

您还可以将其重新写入5.3之前的匿名函数,即la
创建函数()。虽然
create\u function()
函数通常不作为闭包,但您可以使用一些技巧(不使用全局变量)使它们在某些有限的情况下作为闭包工作。将闭合变量直接编码到函数源中。其局限性在于,数据只能单向传输——在;封闭变量只能是“简单”数据类型,如数字、字符串和数组;使用
create\u函数创建的函数永远不会释放,内存泄漏;而且效率也不是很高。但我认为这对于您的示例来说已经足够了(假设您只使用数组和字符串等)


不过,5.3版之前更通用的解决方案是使用对象和方法作为闭包,如hakra的回答所示。

5.3版中添加了anon funcs,所以是的,你是对的。。。不支持:。通过使用常规定义的函数来解决此问题
usort($items,“your\u func\u here”)
。谢谢-问题是我真的不知道匿名函数是如何工作的。例如,我无法计算变量$a、$b和$v是如何使用的。它们来自哪里?将函数声明为常规函数,并将它们作为字符串传入。$a和$b只是usort传递给函数的值,是$item中考虑的两个数组元素。您只需将
函数($b,$a)
作为参数,而不使用实际的比较代码,就可以轻松地将回调更改为反向排序。谢谢Marc。我还没有完全理解你。你能为我构造一个答案中的代码吗?哇,非常详细-谢谢。我必须在自己的类中声明函数吗?或者这些都可以包装到我调用它的类中。当然,如果你已经有了一个类定义,你可以添加回调函数。然后,您应该将它们设置为私有,并在类中调用映射和排序函数,这样它就真的很闪亮了!啊,对不起,我在这里太慢了。是公共函数构造($data)让我感到困惑。我真的不能把它加到我现在的课上。对不起,如果这是显而易见的…这是漫长的一天…当然你不能添加它那里。但是,您可以通过其他一些公共函数传递它,将其分配给私有成员变量,执行回调并完成。它不能通过ctor函数传递。嗯,好的,现在完全丢失了。谢谢你的帮助。我看看我能拼凑些什么。。。
// 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);
$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);