PHP中的闭包……确切地说,它们是什么?何时需要使用它们?

时间:2020-03-06 14:51:08  来源:igfitidea点击:

因此,我以一种不错的,最新的,面向对象的方式进行编程。我经常利用PHP实现的OOP的各个方面,但我想知道何时需要使用闭包。有没有什么专家可以揭示何时实施闭包有用?

解决方案

将来何时需要执行我们现在确定的任务的功能。

例如,如果我们读取一个配置文件,并且其中一个参数告诉我们算法的" hash_method"是"乘"而不是"平方",则可以创建一个闭包,该闭包将在需要散列某些内容的任何地方使用。

可以在config_parser()中创建闭包。它使用config_parser()本地变量(从配置文件)创建一个名为do_hash_method()的函数。每当调用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帖子提供的上下文。当我想在PHP中执行Dan Udey的示例之类的操作时,我使用OO策略模式。在我看来,这比引入一个新的全局函数要好得多,该函数的行为是在运行时确定的。

http://en.wikipedia.org/wiki/Strategy_pattern

我们也可以使用保存PHP中方法名称的变量来调用函数和方法,这很棒。因此,Dan的例子的另一种观点是这样的:

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

当然,如果我们希望它随处可见,则可以将所有内容设为静态...

PHP将在5.3中原生支持闭包。当我们想要仅用于某些特定目的的局部函数时,闭包是很好的选择。 RFC的闭包给出了一个很好的例子:

function replace_spaces ($text) {
    $replacement = function ($matches) {
        return str_replace ($matches[1], ' ', ' ').' ';
    };
    return preg_replace_callback ('/( +) /', $replacement, $text);
}

这使我们可以在replace_spaces()内本地定义replacement函数,而不是:
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 lambda和闭包