代码之家  ›  专栏  ›  技术社区  ›  rg88

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

  •  74
  • rg88  · 技术社区  · 16 年前

    所以我正在以一种漂亮的、最新的、面向对象的方式进行编程。我经常使用PHP实现的OOP的各个方面,但我想知道什么时候需要使用闭包。有没有哪位专家能解释一下什么时候实现闭包是有用的?

    6 回复  |  直到 6 年前
        1
  •  71
  •   Krishnadas PC    6 年前

    PHP将在5.3中支持本机闭包。当您想要一个只用于一些小的、特定用途的本地函数时,闭包是很好的。这个 RFC for closures 举个好例子:

    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;  
     }); 
    

    这里有一个很好的解释 What are php lambdas and closures

        2
  •  15
  •   Dan Udey    16 年前

    当您将来需要一个函数来执行您现在决定的任务时。

    例如,如果您读取一个配置文件,并且其中一个参数告诉您 hash_method 因为你的算法是 multiply 而不是 square ,您可以创建一个闭包,该闭包将在需要散列某个内容的任何位置使用。

    可以在中创建闭包(例如) config_parser() ;它创建一个名为 do_hash_method() 使用局部变量 CONTIONPARSER() (来自配置文件)。无论何时 do_hash_方法() 调用,它可以访问本地范围内的变量 CONTIONPARSER() 即使它不在这个范围内被调用。

    一个很好的假设例子:

    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)
    }
    
        3
  •  15
  •   troelskn    16 年前

    除了技术细节之外,闭包是一种称为面向函数编程的编程风格的基本前提。闭包大致用于与在面向对象编程中使用对象相同的事情;它将数据(变量)与一些代码(函数)绑定在一起,然后您可以将这些代码传递到其他地方。因此,它们会影响你编写程序的方式,或者——如果你不改变你编写程序的方式——它们根本没有任何影响。

    在PHP的上下文中,它们有点奇怪,因为PHP已经非常重视基于类的、面向对象的范式以及旧的过程范式。通常,具有闭包的语言具有完整的词汇范围。为了保持向后兼容性,PHP不会得到这样的结果,所以这意味着闭包在这里与其他语言有点不同。我想我们还没弄清楚它们将如何使用。

        4
  •  10
  •   grossvogel    16 年前

    我喜欢特罗埃尔斯基的文章提供的上下文。当我想在PHP中做丹·乌迪的例子时,我使用了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
    

    当然,如果你想让它在任何地方都可用,你可以让一切都是静态的…

        5
  •  2
  •   Rolf    10 年前

    闭包基本上是在一个上下文中编写定义,但在另一个上下文中运行的函数。javascript在理解这些方面帮助了我很多,因为它们在各地的javascript中都被使用。

    在PHP中,由于函数内部的“全局”(或“外部”)变量的范围和可访问性不同,它们不如在JavaScript中有效。然而,从php 5.4开始,闭包可以在对象内部运行时访问$this对象,这使得它们更加有效。

    这就是闭包的含义,它应该足以理解上面写的内容。

    这意味着应该可以在某个地方编写函数定义,并在函数定义中使用$this变量,然后将函数定义赋给变量(其他人已经给出了语法示例),然后将该变量传递给对象并在对象上下文中调用它,然后函数可以访问和操作通过$this的对象就好像它只是它的另一个方法,而实际上它并没有在该对象的类定义中定义,而是在其他地方定义。

    如果不是很清楚,那么别担心,一旦你开始使用它们,它就会变得清晰。

        6
  •  0
  •   Hisham Dalal    7 年前

    下面是PHP中闭包的示例

    // Author: HishamDalal@gamil.com
    // Publish on: 2017-08-28
    
    class users
    {
        private $users = null;
        private $i = 5;
    
        function __construct(){
            // Get users from database
            $this->users = array('a', 'b', 'c', 'd', 'e', 'f');
        }
    
        function displayUsers($callback){
            for($n=0; $n<=$this->i; $n++){
                echo  $callback($this->users[$n], $n);
            }
        }
    
        function showUsers($callback){
            return $callback($this->users);
    
        }
    
        function getUserByID($id, $callback){
            $user = isset($this->users[$id]) ? $this->users[$id] : null;
            return $callback($user);
        }
    
    }
    
    $u = new users();
    
    $u->displayUsers(function($username, $userID){
        echo "$userID -> $username<br>";
    });
    
    $u->showUsers(function($users){
        foreach($users as $user){
            echo strtoupper($user).' ';
        }
    
    });
    
    $x = $u->getUserByID(2, function($user){
    
        return "<h1>$user</h1>";
    });
    
    echo ($x);
    

    输出:

    0 -> a
    1 -> b
    2 -> c
    3 -> d
    4 -> e
    5 -> f
    
    A B C D E F 
    
    c