- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
本主题扩展至 When do/should I use __construct(), __get(), __set(), and __call() in PHP?其中谈到了 __construct
、__get
和 __set
魔术方法。
从 PHP 5.3 开始,有一个名为 __invoke
的新魔术方法。 __invoke
方法在脚本尝试将对象作为函数调用时被调用。
现在我对这个方法进行了研究,人们把它比作 Java 方法 .run()
- 见 Interface Runnable .
经过长时间的认真思考,我想不出你为什么会调用 $obj();
而不是 $obj->function();
即使您正在迭代对象数组,您仍然会知道要运行的主函数名称。
__invoke
魔术方法也是 PHP 中“仅仅因为你可以,并不意味着你应该”快捷方式的另一个例子,或者在某些情况下这实际上是正确的做法?
最佳答案
__invoke
的使用当您需要 callable 时才有意义那必须保持一些内部状态。假设您要对以下数组进行排序:
$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 function 允许您使用某些函数对数组进行排序,非常简单。但是在这种情况下,我们想使用其内部数组 '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);
}
}
一个实现 __invoke
的 Class 对象,它是一个“可调用的”,它可以在函数可能存在的任何上下文中使用,所以现在我们可以简单地实例化 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'
以下段落反射(reflect)了我的主观意见,因此,如果您愿意,现在可以停止阅读答案;):尽管前面的示例显示了 __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 | closures | anonymous functions 更亲密一些。它更加简洁,因为它不会创建一个完整的类结构来存储外部值。
关于PHP 5.3 魔术方法 __invoke,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/888064/
是否有可能通过使用可变数量参数的 __invoke 魔法方法调用一个类? 我知道在 php 5.6 中有可变参数,但我的版本还没有...... 对于普通的类方法,我可以尝试使用魔术方法 __call
考虑这个类的安排 - 特别是魔术函数 __invoke: class Barman { public function __construct() { // .. .cons
我正在开发一个小型框架(在 JS 中),出于美观和简单的原因,我想知道是否有一种方法可以实现类似于 PHP“__invoke”的东西。 例如: var myClass = function(confi
无法调试这个简单的路由问题,尽管已经看了几个类似的帖子。 TestController is not invokable. The controller class TestControlleris
我想知道这是错误还是正常。假设我有一个具有一些神奇功能的类: class Foo { public function __toString() { return '`__toS
假设我们有如下代码: worker = $worker; } public function __call($name, $arguments) { echo "called\n";
本主题扩展至 When do/should I use __construct(), __get(), __set(), and __call() in PHP?其中谈到了 __construct、_
例如,在下面的代码中: /** * @Route("/patients", service="bundle1.controller.patient.index") */ final class I
例如,在下面的代码中: /** * @Route("/patients", service="bundle1.controller.patient.index") */ final class I
例子: function Queue() { } var q = new Queue(); 当像函数一样调用时,是否可以让 q 调用方法?调用 q() 只会报错: TypeError: object
// in class public function test () { $this->__invoke(); } $inst->test(); 这个测试运行没有任何错误。 我的问题:有什么
我是一名优秀的程序员,十分优秀!