PHP:如何使用带有匿名函数的usort?

5

我有一个数组的数组。

我正在尝试使用以下代码来根据每个主数组元素的字段对主数组进行排序。

$field = $this->sorting;
usort($this->out_table["rows"], function($a, $b) use ($field) {
        return strnatcmp($a[$field], $b[$field]);
});

但我已经有这个了

 Parse error: syntax error, unexpected T_FUNCTION 

针对第二行,即以“usort”开头的那一行,请问我漏掉了什么?

我的php版本是

PHP 5.2.4-2ubuntu5.27 with Suhosin-Patch 0.9.6.2 (cli) (built: Mar 11 2013 14:14:48)

3
你正在使用哪个PHP版本?请确保其版本号不低于>= 5.30。详细内容请参考:http://php.net/manual/en/functions.anonymous.php。 - ʰᵈˑ
4
PHP 5.2不支持匿名函数。匿名函数是Closure类的实例,根据官方文档,该类在5.3版本才被引入。建议升级你的PHP版本,因为5.2版本已经过时了。 - Elias Van Ootegem
为什么有人给我点了踩?难道用户不可能不知道闭包是什么时候引入的吗?如果我已经拥有所有信息,我就不会在这里发问了! - realtebo
1
@realtebo:放松一点... hd 是第一个花时间回答这个问题的人,而且他还花时间解释为什么有人可能会对这个问题进行-1评分。不要怪他,他只是想帮忙... - Elias Van Ootegem
1
@realtebo: "所以最近引入了闭包"... PHP 5.3发布已经有将近6年的时间了(http://php.net/ChangeLog-5.php#5.3.0)。甚至在此期间已经停止维护(http://php.net/eol.php)我不会说闭包是最近才被引入的... - axiac
显示剩余5条评论
3个回答

4

PHP 5.2不支持匿名函数。匿名函数是Closure类的实例,根据文档所述,Closure类直到5.3才被引入... PS:升级你的PHP版本,5.2已经过时了。

但现在最好编写自己的类,将$field值传递给该类的实例,并使用数组样式的可调用参数:

class Sorter
{
    protected $field = null;
    public function __construct($field)
    {
        $this->field = $field;
    }
    public function sortCallback($a, $b)
    {
        return strnatcmp($a[$this->field], $b[$this->field]);
    }
}
$sorter = new Sorter($field);
usort($this->out_table["rows"], array($sorter, 'sortCallback'));

基本上,一个闭包实例所做的就是匿名函数。在这种情况下,匿名函数只是一种语法糖。这种类的优点是你可以添加更多的排序回调方法,并将其保持为一个实用程序类,例如具有“sortAscending”和“sortDescending”回调方法。此外,您可以在实例上设置选项,使排序器在需要时使用严格(类型和值)比较...

1
删除了我的回答,因为我更喜欢这种方式。 - ʰᵈˑ
@ʰᵈˑ:你不必删除你的答案。因为有些人可能不愿意实现我的建议修复(不喜欢/不了解/不使用OOP的人确实存在)。对于他们来说,因为它在技术上是有效的,所以你的答案是可以接受的。特别是因为,至少对我来说,它展示了面向对象编程的价值=>不必使用“global”等等... - Elias Van Ootegem
我没有想到那个角度 :) 就个人而言,我不喜欢使用 global,并希望 OP 能够接受这个答案,因为 global 可能会带来一些潜在的问题。 - ʰᵈˑ

4

匿名函数在PHP 5.3中被引入。

如果你使用的是旧版本的PHP,你需要使用create_function()函数。它也会产生一个匿名函数,没有功能上的区别,只是语法不太好看,并且没有use的等效功能:

$field = $this->sorting;
usort(
    $this->out_table["rows"],
    create_function(
        // the list of arguments
        '$a, $b',
        // the function body (everything you normally put between { and }
        'global $field; return strnatcmp($a[$field], $b[$field]);'
    )
);

为避免使用global(如果将此代码放在函数/方法中,它甚至不起作用),您可以尝试编写一个将$field作为参数并创建比较函数的函数(类似于JavaScript闭包)。
这很容易使用匿名函数完成(但不需要),也可以使用create_function()轻松完成(虽然需要转义)。
function fn($fld)
{
    $fld = addslashes($fld);
    return create_function(
        '$a, $b',                                          // arguments
        "return strnatcmp(\$a['$fld'], \$b['$fld']);"      // function body
    );
}

usort($this->out_table["rows"], fn($field));

函数fn()基本上以旧版PHP(5.3之前)的方式从您的代码中创建匿名函数。

请注意,由于比较函数的主体是使用参数$fld的内容生成的,因此对于某些$fld的值,它可能会产生运行时错误(实际上是编译错误,但由于生成的函数主体是在运行时创建和解析的,因此直到太晚才能检测到这些错误)。

另一个比create_function()更好的选项是为此目的创建一个类,如this answer所述。


1

根据文档,匿名函数是在5.30版本中引入的。您正在运行低于5.30的版本。

  • 升级您的PHP版本(先备份服务器)
  • 使用下面的解决方案

usort($this->out_table["rows"], 'mySort');
function mySort($a, $b) {
    global $field;
    return strnatcmp($a[$field], $b[$field]);
}

当然!我实际上赞同你的答案,并建议不要使用global - ʰᵈˑ
1
+1 给匿名的踩票加一,因为这个回答在之前的评论中提到了增加的价值。 - Elias Van Ootegem
这段代码由于多种原因根本无法工作。其中之一:sort函数已经被PHP定义,不能再次定义。然后在usort()开始之前,该函数仅使用未定义的参数$a$b调用一次。应该改为usort($this->out_table["rows"], 'my_sort'); function my_sort(...) - axiac
@EliasVanOotegem 我是那个点了踩的人。我在之前的评论中已经解释了原因。在你看来,一个回答应该包含多少错误才能够被踩呢? - axiac
@axiac:没有仔细看代码。但你是对的,根据hd在我的回答下面和原帖下面发表的评论,我会给他一些怀疑的余地,并纠正这些错误,因为我觉得这些错误很愚蠢(因为太匆忙了),而不是在这种情况下进行贬低。 - Elias Van Ootegem
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接