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

时间:2020-12-27 20:56:01

So I'm programming along in a nice, up to date, object oriented fashion. I regularly make use of the various aspects of OOP that PHP implements but I am wondering when might I need to use closures. Any experts out there that can shed some light on when it would be useful to implement closures?

我用一种很好的,最新的,面向对象的方式编程。我经常使用PHP实现的OOP的各个方面,但我想知道何时需要使用闭包。是否有专家能够阐明什么时候实施闭包是有用的?

6 个解决方案

#1


64  

PHP will support closures natively in 5.3. A closure is good when you want a local function that's only used for some small, specific purpose. The RFC for closures give a good example:

PHP将在5.3中支持闭包。当您希望局部函数只用于某个小的、特定的目的时,闭包是好的。用于闭包的RFC就是一个很好的例子:

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

This lets you define the replacement function locally inside replace_spaces(), so that it's not:
1) Cluttering up the global namespace
2) Making people three years down the line wonder why there's a function defined globally that's only used inside one other function

这使您可以在replace_spaces()内部本地定义替换函数,这样就不会:1)将全局命名空间弄得一团糟2)让人们在三年之后怀疑为什么有一个全局定义的函数只在另一个函数中使用

It keeps things organized. Notice how the function itself has no name, it simply is defined and assigned as a reference to $replacement.

它使事情有条理。注意这个函数本身没有名称,它只是被定义并指定为$替换的引用。

But remember, you have to wait for PHP 5.3 :)

但是请记住,您必须等待PHP 5.3:)

You can also access variables outside it's scope into a closure using the keyword use. Consider this example.

您还可以使用关键字使用来访问外部变量的范围。考虑一下这个例子。

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

An excellent explanation is given here What are php lambdas and closures

这里给出了一个很好的解释,php lambdas和闭包是什么

#2


14  

When you will need a function in the future which performs a task that you have decided upon now.

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

For example, if you read a config file and one of the parameters tells you that the hash_method for your algorithm is multiply rather than square, you can create a closure that will be used wherever you need to hash something.

例如,如果您读取一个配置文件,其中一个参数告诉您算法的hash_method是乘法而不是正方形,那么您可以创建一个闭包,该闭包将在需要散列的任何地方使用。

The closure can be created in (for example) config_parser(); it creates a function called do_hash_method() using variables local to config_parser() (from the config file). Whenever do_hash_method() is called, it has access to variables in the local scope ofconfig_parser() even though it's not being called in that scope.

可以在(例如)config_parser()中创建闭包;它使用配置文件中的config_parser()本地变量创建一个名为do_hash_method()的函数。无论何时调用do_hash_method(),它都可以访问本地范围ofconfig_parser()中的变量,即使在那个范围中没有调用它。

A hopefully good hypothetical example:

一个很好的假设例子:

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


14  

Apart from the technical details, closures are a fundamental pre-requisite for a programming style known as function oriented programming. A closure is roughly used for the same thing as you use an object for in object oriented programming; It binds data (variables) together with some code (a function), that you can then pass around to somewhere else. As such, they impact on the way that you write programs or - if you don't change the way you write your programs - they don't have any impact at all.

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

In the context of PHP, they are a little odd, since PHP already is heavy on the class based, object oriented paradigm, as well as the older procedural one. Usually, languages that have closures, has full lexical scope. To maintain backwards compatibility, PHP is not going to get this, so that means that closures are going to be a little different here, than in other languages. I think we have yet to see exactly how they will be used.

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

#4


8  

I like the context provided by troelskn's post. When I want to do something like Dan Udey's example in PHP, i use the OO Strategy Pattern. In my opinion, this is much better than introducing a new global function whose behavior is determined at runtime.

我喜欢troelskn的文章所提供的内容。当我想做一些像Dan Udey在PHP中的例子时,我使用了OO策略模式。在我看来,这比引入一个新的全局函数要好得多,该函数的行为是在运行时确定的。

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

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

You can also call functions and methods using a variable holding the method name in PHP, which is great. so another take on Dan's example would be something like this:

您还可以使用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

of course, if you want it to be available everywhere, you could just make everything static...

当然,如果你想让它无处不在,你可以让一切都静止不动……

#5


1  

A closure is basically a function for which you write the definition in one context but run in another context. Javascript helped me a lot with understanding these, because they are used in JavaScript all over the place.

闭包基本上是一个函数,它在一个上下文中编写定义,但在另一个上下文中运行。Javascript帮助我理解这些,因为它们在Javascript中随处可见。

In PHP, they are less effective than in JavaScript, due to differences in the scope and accessibility of "global" (or "external") variables from within functions. Yet, starting with PHP 5.4, closures can access the $this object when run inside an object, this makes them a lot more effective.

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

This is what closures are about, and it should be enough to understand what is written above.

这就是闭包的意义所在,理解上面写的内容就足够了。

This means that it should be possible to write a function definition somewhere, and use the $this variable inside the function definition, then assign the function definition to a variable (others have given examples of the syntax), then pass this variable to an object and call it in the object context, the function can then access and manipulate the object through $this as if it was just another one of it's methods, when in fact it's not defined in the class definition of that object, but somewhere else.

这意味着它应该可以写一个函数定义,并使用美元这个变量在函数定义,然后将函数定义分配给一个变量(别人给了语法的例子),那么这个变量传递给一个对象,并调用它的对象上下文,函数可以访问和操作对象通过$ This好像这只是另一个方法,而事实上它不是在类定义中定义的对象,但在其他地方。

If it's not very clear, then don't worry, it will become clear once you start using them.

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

#6


0  

Here are examples for closures in php

这里有一些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);

Output:

输出:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

c

#1


64  

PHP will support closures natively in 5.3. A closure is good when you want a local function that's only used for some small, specific purpose. The RFC for closures give a good example:

PHP将在5.3中支持闭包。当您希望局部函数只用于某个小的、特定的目的时,闭包是好的。用于闭包的RFC就是一个很好的例子:

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

This lets you define the replacement function locally inside replace_spaces(), so that it's not:
1) Cluttering up the global namespace
2) Making people three years down the line wonder why there's a function defined globally that's only used inside one other function

这使您可以在replace_spaces()内部本地定义替换函数,这样就不会:1)将全局命名空间弄得一团糟2)让人们在三年之后怀疑为什么有一个全局定义的函数只在另一个函数中使用

It keeps things organized. Notice how the function itself has no name, it simply is defined and assigned as a reference to $replacement.

它使事情有条理。注意这个函数本身没有名称,它只是被定义并指定为$替换的引用。

But remember, you have to wait for PHP 5.3 :)

但是请记住,您必须等待PHP 5.3:)

You can also access variables outside it's scope into a closure using the keyword use. Consider this example.

您还可以使用关键字使用来访问外部变量的范围。考虑一下这个例子。

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

An excellent explanation is given here What are php lambdas and closures

这里给出了一个很好的解释,php lambdas和闭包是什么

#2


14  

When you will need a function in the future which performs a task that you have decided upon now.

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

For example, if you read a config file and one of the parameters tells you that the hash_method for your algorithm is multiply rather than square, you can create a closure that will be used wherever you need to hash something.

例如,如果您读取一个配置文件,其中一个参数告诉您算法的hash_method是乘法而不是正方形,那么您可以创建一个闭包,该闭包将在需要散列的任何地方使用。

The closure can be created in (for example) config_parser(); it creates a function called do_hash_method() using variables local to config_parser() (from the config file). Whenever do_hash_method() is called, it has access to variables in the local scope ofconfig_parser() even though it's not being called in that scope.

可以在(例如)config_parser()中创建闭包;它使用配置文件中的config_parser()本地变量创建一个名为do_hash_method()的函数。无论何时调用do_hash_method(),它都可以访问本地范围ofconfig_parser()中的变量,即使在那个范围中没有调用它。

A hopefully good hypothetical example:

一个很好的假设例子:

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


14  

Apart from the technical details, closures are a fundamental pre-requisite for a programming style known as function oriented programming. A closure is roughly used for the same thing as you use an object for in object oriented programming; It binds data (variables) together with some code (a function), that you can then pass around to somewhere else. As such, they impact on the way that you write programs or - if you don't change the way you write your programs - they don't have any impact at all.

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

In the context of PHP, they are a little odd, since PHP already is heavy on the class based, object oriented paradigm, as well as the older procedural one. Usually, languages that have closures, has full lexical scope. To maintain backwards compatibility, PHP is not going to get this, so that means that closures are going to be a little different here, than in other languages. I think we have yet to see exactly how they will be used.

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

#4


8  

I like the context provided by troelskn's post. When I want to do something like Dan Udey's example in PHP, i use the OO Strategy Pattern. In my opinion, this is much better than introducing a new global function whose behavior is determined at runtime.

我喜欢troelskn的文章所提供的内容。当我想做一些像Dan Udey在PHP中的例子时,我使用了OO策略模式。在我看来,这比引入一个新的全局函数要好得多,该函数的行为是在运行时确定的。

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

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

You can also call functions and methods using a variable holding the method name in PHP, which is great. so another take on Dan's example would be something like this:

您还可以使用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

of course, if you want it to be available everywhere, you could just make everything static...

当然,如果你想让它无处不在,你可以让一切都静止不动……

#5


1  

A closure is basically a function for which you write the definition in one context but run in another context. Javascript helped me a lot with understanding these, because they are used in JavaScript all over the place.

闭包基本上是一个函数,它在一个上下文中编写定义,但在另一个上下文中运行。Javascript帮助我理解这些,因为它们在Javascript中随处可见。

In PHP, they are less effective than in JavaScript, due to differences in the scope and accessibility of "global" (or "external") variables from within functions. Yet, starting with PHP 5.4, closures can access the $this object when run inside an object, this makes them a lot more effective.

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

This is what closures are about, and it should be enough to understand what is written above.

这就是闭包的意义所在,理解上面写的内容就足够了。

This means that it should be possible to write a function definition somewhere, and use the $this variable inside the function definition, then assign the function definition to a variable (others have given examples of the syntax), then pass this variable to an object and call it in the object context, the function can then access and manipulate the object through $this as if it was just another one of it's methods, when in fact it's not defined in the class definition of that object, but somewhere else.

这意味着它应该可以写一个函数定义,并使用美元这个变量在函数定义,然后将函数定义分配给一个变量(别人给了语法的例子),那么这个变量传递给一个对象,并调用它的对象上下文,函数可以访问和操作对象通过$ This好像这只是另一个方法,而事实上它不是在类定义中定义的对象,但在其他地方。

If it's not very clear, then don't worry, it will become clear once you start using them.

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

#6


0  

Here are examples for closures in php

这里有一些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);

Output:

输出:

0 -> a
1 -> b
2 -> c
3 -> d
4 -> e
5 -> f

A B C D E F 

c