我知道这是一个旧的帖子,但今天我遇到了另一个例子,可能会受益于另一种方法。我有一个案例,我想使用特定的键,以便我可以抽象出实际的支持函数。这导致找到一个版本,使用包装器函数返回一个匿名函数,利用'use'命令词来提供在我的类中用于排序的键的名称(在我的情况下,它是分配给我正在进行排序的类属性之一的[嵌套]类上的属性中的关键字 - 即我根据'尺寸'实例的属性对'项'的属性进行排序,并希望能够按宽度、高度、长度或重量等排序)。然后,为了获取回调的函数,您只需使用要用于排序结果的键名称调用此包装器函数:
public $items;
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;
};
}
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 变量来实现。由于我还需要确保在进行任何比较之前已经计算了这些值,所以我可以根据键在我的函数中触发它:
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;
};
}
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!');
}
注意:通过这种方式计算值会产生开销,因为除了列表中的第一个和最后一个项外,所有其他项在技术上都会被计算两次,这是多余的。但在这种情况下,我的列表不是很长,并且在进行二进制排序时有时需要比较两个项,因此仍然更可取。对于大型数据集,预先计算排序方法外部的值可能更明智。