一个类中的usort函数

55

我有一个函数可以对多维数组中的数据进行排序,如下所示:

<?php  
$data = array();  
$data[] = array("name" => "James");  
$data[] = array("name" => "andrew");  
$data[] = array("name" => "Fred");  

function cmp($a, $b)  
{  
    return strcasecmp($a["name"], $b["name"]);  
}  

usort($data, "cmp");  

var_dump($data);  
?>  

当我运行这段代码时,它按照姓名升序的顺序返回了预期结果。然而,我现在需要将其用于一个类中。

<?php
class myClass  
{  
    function getData()  
    {  
        // gets all data
        $this -> changeOrder($data);
    }  

    function changeOrder(&$data)  
    {  
         usort($data, "order_new");
    }

    function order_new($a, $b)  
    {  
        return strcasecmp($a["name"], $b["name"]);  
    }
}
?>

当我使用这个方法时,我得到以下警告:警告:usort()函数期望第二个参数是一个有效的回调函数,但没有找到或无效的函数名'order_new'。

当我将order_new函数放在changeOrder函数中时,它可以正常工作,但我遇到了致命错误:无法重新声明order_new(),所以我不能这样做。有什么建议吗?


1
你在查找类似问题时,好像错过了 这个答案,是吗? - raina77ow
看到了,但类名不起作用。$this可以。 - Marinus
你在尝试使用类名调用这个函数之前,是否将它声明为静态的了? - raina77ow
6个回答

115

order_new 是一个类方法而不是全局函数。如PHP手册所建议的,你可以在这种情况下使用

usort($data, array($this, "order_new")); 
或者声明order_new为静态变量并使用
usort($data, array("myClass", "order_new")); 

18
如果你正在使用命名空间,翻译以下代码:usort($data, array("MyBundle\PathTo\MyClass", "orderNew"));使用命名空间时,对于上述代码可以这样翻译:usort($data, array("我的束(MyBundle)\路径(PathTo)\我的类(MyClass)", "orderNew")); - Limon Monte

9

将代码更改为usort($data, array($this, "order_new"));


5

需要考虑的一件事是,如果变量通过引用传递到您的方法中,usort()似乎在引用变量的上下文中执行,而不是在当前方法中执行。因此,您需要在类引用中提供完整的命名空间,如下所示:

usort($data, ['My\NameSpace\MyClass', 'order_new']); 

2
有趣。它在我的项目中按原样工作,但要用单引号。我已经更新以反映这一点。 - beltashazzar
1
非常感谢。在我的情况下,我使用了双引号。 - tmuecksch

5
 usort($data, array($this,"order_new"));

当您在类实例中引用一个函数时,您需要使用 callable。请参见callable

已实例化对象的方法将作为一个数组传递,包含在索引0处的对象和在索引1处的方法名称。


1

我知道这是一个旧的帖子,但今天我遇到了另一个例子,可能会受益于另一种方法。我有一个案例,我想使用特定的键,以便我可以抽象出实际的支持函数。这导致找到一个版本,使用包装器函数返回一个匿名函数,利用'use'命令词来提供在我的类中用于排序的键的名称(在我的情况下,它是分配给我正在进行排序的类属性之一的[嵌套]类上的属性中的关键字 - 即我根据'尺寸'实例的属性对'项'的属性进行排序,并希望能够按宽度、高度、长度或重量等排序)。然后,为了获取回调的函数,您只需使用要用于排序结果的键名称调用此包装器函数:

/**
 * list of items
 *
 * @var Item[]
 */
public $items;

/**
 * @param string $key
 * @return \Closure
 */
private static function keySort($key) {
    return function ($ia, $ib) use ($key) {
        if($ia->dimensions->$key == $ib->dimensions->$key) return 0;
        return ($ia->dimensions->$key < $ib->dimensions->$key) ? -1 : 1;
    };
}

/**
 * return the list of items in the items array sorted by the value
 *   of the property specified by $key
 *
 * @param string $key
 * @return Item[]
 * @throws \Exception
 */
public function sortItemsByKey($key)
{
    if(in_array($key, array( 'width', 'length', 'height', 'weight', ))) {
        return usort($this->items, static::keySort($key));
    } else
        throw new \Exception(__METHOD__ . ' invalid sort key!');
}

这使我能够使用 static:: 或 self:: 来调用它(在这种情况下,我甚至可以将其包装为非静态函数,因为我唯一担心的是获取调用但函数返回)。我很快发现另一个好处是我的 dimensions 对象还有一些“计算”字段,例如周长、体积和尺寸重量。但问题在于尺寸重量取决于您是在国内还是国际运输物品,因此我需要告诉我的“calculateDimensionalWeight”函数是否应该使用国际运输的值。好了,使用这种方法,我可以通过向包装器函数传递一个额外的参数并将其添加到 use 变量来实现。由于我还需要确保在进行任何比较之前已经计算了这些值,所以我可以根据键在我的函数中触发它:
/**
 * @param string $key
 * @param bool $intl // only used for dimensional weight
 * @return \Closure
 */
private static function keySort($key,$intl=false) {
    return function ($ia, $ib) use ($key,$intl) {
        switch($key) {
            case 'girth':
                $ia->dimensions->calculateGirth();
                $ib->dimensions->calculateGirth();
                break;
            case 'dimweight':
                $ia->dimensions->calculateDimensionalWeight($intl);
                $ib->dimensions->calculateDimensionalWeight($intl);
                break;
            case 'volume':
                $ia->dimensions->calculateVolume();
                $ib->dimensions->calculateVolume();
                break;
        }
        if($ia->dimensions->$key == $ib->dimensions->$key) return 0;
        return ($ia->dimensions->$key < $ib->dimensions->$key) ? -1 : 1;
    };
}

/**
 * return the list of items in the items array sorted by the value
 *
 * @param string $key
 * @param bool $intl  (only used for dimensional weight sorts on international shipments)
 * @return Item[]
 * @throws \Exception
 */
public function sortItemsByKey($key,$intl=false)
{
    if(in_array($key, array('value','collect', 'width', 'length', 'height', 'weight', 'girth', 'dimweight', 'volume'))) {
        return usort($this->items, static::keySort($key,$intl));
    } else
        throw new \Exception(__METHOD__ . ' invalid sort key!');
}

注意:通过这种方式计算值会产生开销,因为除了列表中的第一个和最后一个项外,所有其他项在技术上都会被计算两次,这是多余的。但在这种情况下,我的列表不是很长,并且在进行二进制排序时有时需要比较两个项,因此仍然更可取。对于大型数据集,预先计算排序方法外部的值可能更明智。

0
// If order_new is a NORMAL function 
usort($data, [$this, 'order_new']);      // self ref object, function name  

// If order_new is a STATIC function 
usort($data, [__CLASS__, 'order_new']);  // string, function name 

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