当您需要一个必须维护某些内部状态的可调用对象时,使用 是__invoke
有意义的。假设您要对以下数组进行排序:
$arr = [
['key' => 3, 'value' => 10, 'weight' => 100],
['key' => 5, 'value' => 10, 'weight' => 50],
['key' => 2, 'value' => 3, 'weight' => 0],
['key' => 4, 'value' => 2, 'weight' => 400],
['key' => 1, 'value' => 9, 'weight' => 150]
];
usort函数允许您使用某些函数对数组进行排序,非常简单。但是在这种情况下,我们想使用它的内部数组'value'
键对数组进行排序,可以这样做:
$comparisonFn = function($a, $b) {
return $a['value'] < $b['value'] ? -1 : ($a['value'] > $b['value'] ? 1 : 0);
};
usort($arr, $comparisonFn);
// ['key' => 'w', 'value' => 2] will be the first element,
// ['key' => 'w', 'value' => 3] will be the second, etc
现在也许您需要再次对数组进行排序,但是这次使用'key'
作为目标键,有必要重写函数:
usort($arr, function($a, $b) {
return $a['key'] < $b['key'] ? -1 : ($a['key'] > $b['key'] ? 1 : 0);
});
如您所见,该函数的逻辑与前一个相同,但是由于需要使用不同的键进行排序,我们不能重用前一个。这个问题可以通过在__invoke
方法中封装比较逻辑并定义要在其构造函数中使用的键的类来解决:
class Comparator {
protected $key;
public function __construct($key) {
$this->key = $key;
}
public function __invoke($a, $b) {
return $a[$this->key] < $b[$this->key] ?
-1 : ($a[$this->key] > $b[$this->key] ? 1 : 0);
}
}
实现它的 Class 对象__invoke
是“可调用的”,它可以在函数可能存在的任何上下文中使用,所以现在我们可以简单地实例化Comparator
对象并将它们传递给usort
函数:
usort($arr, new Comparator('key')); // sort by 'key'
usort($arr, new Comparator('value')); // sort by 'value'
usort($arr, new Comparator('weight')); // sort by 'weight'
以下段落反映了我的主观意见,因此,如果您愿意,现在可以停止阅读答案;):尽管前面的示例显示了 非常有趣的用法__invoke
,但这种情况很少见,我会避免使用它,因为它确实可以完成令人困惑的方式,通常有更简单的实现替代方案。在同一排序问题中的一个替代示例是使用返回比较函数的函数:
function getComparisonByKeyFn($key) {
return function($a, $b) use ($key) {
return $a[$key] < $b[$key] ? -1 : ($a[$key] > $b[$key] ? 1 : 0);
};
}
usort($arr, getComparisonByKeyFn('weight'));
usort($arr, getComparisonByKeyFn('key'));
usort($arr, getComparisonByKeyFn('value'));
虽然这个例子需要对lambdas有更多的了解| 关闭| 匿名函数更简洁,因为它不会创建一个完整的类结构来存储外部值。