我以一种良好的、最新的面向对象的方式进行编程。我经常利用PHP实现的各种面向对象编程方面,但我想知道何时需要使用闭包。有没有专家可以解释一下在什么情况下实现闭包会有用?
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
函数,这样它就不会:
它使事情井然有序。请注意,函数本身没有名称,它只是被定义并分配为对$replacement
的引用。
但请记住,您必须等待PHP 5.3 :)
除了技术细节外,闭包对于一种称为函数导向编程的编程风格是基本前提。在面向对象编程中,闭包大致用于与对象相同的目的;它将数据(变量)与一些代码(函数)绑定在一起,然后可以将其传递到其他地方。因此,它们影响您编写程序的方式 - 如果您不改变编写程序的方式,则它们根本没有任何影响。
在 PHP 的上下文中,它们有点奇怪,因为 PHP 已经很重视基于类的面向对象范式以及旧的过程范式。通常,拥有闭包的语言具有完全的词法作用域。为了保持向后兼容性,PHP 将不会获得这个特性,这意味着闭包在这里与其他语言有所不同。我认为我们还需要看到它们将如何被使用。
当你未来需要执行一个你现在已经决定的任务时,可以使用函数。
例如,如果你读取配置文件并发现其中一个参数告诉你算法的hash_method
是multiply
而不是square
,你可以创建一个闭包,它可以在任何需要哈希某些内容的地方使用。
这个闭包可以在(例如)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)
}
我喜欢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
当然,如果您希望它在每个地方都可用,您可以将所有内容都设为静态的...
// 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
闭包:
MDN认为它有最好的解释:
闭包是一个函数与其周围状态(词法环境)的引用组合在一起,即一个闭包允许你从内部函数中访问外部函数的作用域。
也就是说,闭包是具有访问父级作用域变量的函数。闭包允许我们方便地动态创建函数,因为在某些情况下,函数只需要在一个地方使用(回调函数、可调用参数)。
示例:
$arr = [1,2,3,3];
$outersScopeNr = 2;
// The second arg in array_filter is a closure
// It would be inconvenient to have this function in global namespace
// The use keyword lets us access a variable in an outer scope
$newArr = array_filter($arr, function ($el) use ($outersScopeNr) {
return $el === 3 || $el === $outersScopeNr;
});
var_dump($newArr);
// array (size=3)
// 1 => int 2
// 2 => int 3
// 3 => int 3
<?php
$param='ironman';
function sayhello(){
$param='captain';
$func=function () use ($param){
$param='spiderman';
};
$func();
echo $param;
}
sayhello();
?>
//output captain
//and if we pass variable as a reference as(&$param) then output would be spider man;
sayhello()
中,$param='captain'
是局部变量。
在 sayhello()
上面的 $param='ironman'
是全局变量。如果你想在脚本中只有一个 $param
变量,你应该在 sayhello()
函数内调用:
global $param;
- vlakov