所以我正在以一种不错的,最新的,面向对象的方式编程.我经常使用PHP实现的OOP的各个方面,但我想知道何时需要使用闭包.那里的任何专家都可以阐明何时实现闭包有用?
PHP将在5.3中原生支持闭包.当你想要一个仅用于某些小的特定目的的本地函数时,闭包是很好的.闭包的RFC给出了一个很好的例子:
function replace_spaces ($text) { $replacement = function ($matches) { return str_replace ($matches[1], ' ', ' ').' '; }; return preg_replace_callback ('/( +) /', $replacement, $text); }
这允许你在replacement
本地内部定义函数replace_spaces()
,因此它不是:
1)使全局命名空间混乱
2)让人们三年下线,想知道为什么全局定义的函数只用在另一个函数中
它保持井井有条.注意函数本身没有名称,它只是被定义并指定为引用$replacement
.
但请记住,你必须等待PHP 5.3 :)
您还可以使用关键字将其范围外的变量访问到闭包中use
.考虑这个例子.
// Set a multiplier $multiplier = 3; // Create a list of numbers $numbers = array(1,2,3,4); // Use array_walk to iterate // through the list and multiply array_walk($numbers, function($number) use($multiplier){ echo $number * $multiplier; });
这里给出了一个很好的解释什么是php lambdas和closures
如果您将来需要一个执行您现在已决定的任务的功能.
例如,如果您读取配置文件并且其中一个参数告诉hash_method
您算法multiply
而不是square
,则可以创建一个闭包,可以在需要散列内容的地方使用.
封闭可以在(例如)中创建config_parser()
; 它创建了一个do_hash_method()
使用变量本地的函数config_parser()
(来自配置文件).无论什么时候do_hash_method()
被调用,它都可以访问本地范围内的变量,config_parser()
即使它没有在该范围内被调用.
一个有希望的好假设的例子:
function config_parser() { // Do some code here // $hash_method is in config_parser() local scope $hash_method = 'multiply'; if ($hashing_enabled) { function do_hash_method($var) { // $hash_method is from the parent's local scope if ($hash_method == 'multiply') return $var * $var; else return $var ^ $var; } } } function hashme($val) { // do_hash_method still knows about $hash_method // even though it's not in the local scope anymore $val = do_hash_method($val) }
除了技术细节之外,闭包是编程风格(称为功能导向编程)的基本先决条件.闭包大致用于在面向对象编程中使用对象时的相同内容; 它将数据(变量)与某些代码(函数)绑定在一起,然后您可以将其传递到其他位置.因此,它们会影响您编写程序的方式,或者 - 如果您不改变编写程序的方式 - 它们根本没有任何影响.
在PHP的上下文中,它们有点奇怪,因为PHP已经在基于类,面向对象的范例以及较旧的程序范例上沉重.通常,具有闭包的语言具有完整的词法范围.为了保持向后兼容性,PHP不会得到这个,所以这意味着闭包在这里会比在其他语言中有所不同.我想我们还没有看到它们将如何被使用.
我喜欢troelskn的帖子提供的上下文.当我想在Dan中使用Dan Udey的例子时,我会使用OO策略模式.在我看来,这比引入一个新的全局函数要好得多,该函数的行为是在运行时确定的.
http://en.wikipedia.org/wiki/Strategy_pattern
您还可以使用在PHP中保存方法名称的变量来调用函数和方法,这很棒.所以对丹的例子的另一种看法是这样的:
class ConfigurableEncoder{ private $algorithm = 'multiply'; //default is multiply public function encode($x){ return call_user_func(array($this,$this->algorithm),$x); } public function multiply($x){ return $x * 5; } public function add($x){ return $x + 5; } public function setAlgorithm($algName){ switch(strtolower($algName)){ case 'add': $this->algorithm = 'add'; break; case 'multiply': //fall through default: //default is multiply $this->algorithm = 'multiply'; break; } } } $raw = 5; $encoder = new ConfigurableEncoder(); // set to multiply echo "raw: $raw\n"; // 5 echo "multiply: " . $encoder->encode($raw) . "\n"; // 25 $encoder->setAlgorithm('add'); echo "add: " . $encoder->encode($raw) . "\n"; // 10
当然,如果你想让它随处可用,你可以让一切都变得静止......