Closure, anonymous function, was introduced in php5.3, also known as Anonymous functions. The literal meaning is a function without a defined name. For example, the following code (the file name is do.php)
<?phpfunction A() {return 100; };function B(Closure $callback) {return $callback(); }$a = B(A());print_r($a);//输出:Fatal error: Uncaught TypeError: Argument 1 passed to B() must be an instance of Closure, integer given, called in D:\web\test\do.php on line 11 and defined in D:\web\test\do.php:6 Stack trace: #0 D:\web\test\do.php(11): B(100) #1 {main} thrown in D:\web\test\do.php on line 6?>
A() here can never be used as a parameter of B, because A is not an "anonymous" function.
So it should be changed to this:
<?php$f = function () {return 100; };function B(Closure $callback) {return $callback(); }$a = B($f);print_r($a);//输出100
<?$func = function( $param ) {echo $param; };$func( 'hello word' );//输出:hello word
Use anonymous functions as parameters in ordinary functions Passed in, it can also be returned. This implements a simple closure.
I will give you three examples below:
<?php//例一 //在函数里定义一个匿名函数,并且调用它function printStr() {$func = function( $str ) {echo $str; };$func( ' hello my girlfriend ! ' ); } printStr();//输出 hello my girlfriend ! //例二 //在函数中把匿名函数返回,并且调用它function getPrintStrFunc() {$func = function( $str ) {echo $str; };return $func; }$printStrFunc = getPrintStrFunc();$printStrFunc( ' do you love me ? ' );//输出 do you love me ? //例三 //把匿名函数当做参数传递,并且调用它function callFunc( $func ) {$func( ' no!i hate you ' ); }$printStrFunc = function( $str ) {echo $str.'<br>'; }; callFunc( $printStrFunc );//也可以直接将匿名函数进行传递。如果你了解js,这种写法可能会很熟悉callFunc( function( $str ) {echo $str; //输出no!i hate you } );
The closure can save the code block it is in. Some variables and values of the context. By default in PHP, anonymous functions cannot call context variables in the code block where they are located, but need to use the use keyword.
Let’s take a look at another example (well, I’m short of money, I’m vulgar):
<?phpfunction getMoney() {$rmb = 1;$dollar = 8;$func = function() use ( $rmb ) {echo $rmb;echo $dollar; };$func(); } getMoney();//输出:1
As you can see, dollar is not declared in the use keyword, It cannot be obtained in this anonymous function, so pay attention to this issue during development.
Some people may think about whether it is possible to change the context variables in an anonymous function, but I found that it seems not possible:
<?phpfunction getMoney() {$rmb = 1;$func = function() use ( $rmb ) {echo $rmb.'<br>';//把$rmb的值加1$rmb++; };$func();echo $rmb; } getMoney();//输出: //1 //1
Um, the original use referenced Clone is just a copy of the variable. But what if I want to fully reference the variable instead of copying it? To achieve this effect, actually add an & symbol before the variable:
<?phpfunction getMoney() {$rmb = 1;$func = function() use ( &$rmb ) {echo $rmb.'<br>';//把$rmb的值加1$rmb++; };$func();echo $rmb; } getMoney();//输出: //1 //2
Okay, then the anonymous function will You can now reference context variables. If the anonymous function is returned to the outside world, the anonymous function will save the variables referenced by use, but the outside world will not be able to obtain these variables. In this way, the concept of 'closure' may be clearer.
According to the description, let’s change the above example:
<?phpfunction getMoneyFunc() {$rmb = 1;$func = function() use ( &$rmb ) {echo $rmb.'<br>';//把$rmb的值加1$rmb++; };return $func; }$getMoney = getMoneyFunc();$getMoney();$getMoney();$getMoney();//输出: //1 //2 //3
Okay, so much, so what if we want to call an anonymous function in a class? Go directly to demo
<?phpclass A {public static function testA() {return function($i) { //返回匿名函数return $i+100; }; } }function B(Closure $callback) {return $callback(200); }$a = B(A::testA());print_r($a);//输出 300
where A::testA() returns an unnamed funciton.
The Closure in the above example is just a global anonymous function. Well, now we want to specify that a class has an anonymous function. It can also be understood that the access scope of this anonymous function is no longer global, but the access scope of a class.
Then we need to bind "an anonymous function to a class".
<?phpclass A {public $base = 100; }class B {private $base = 1000; }$f = function () {return $this->base + 3; };$a = Closure::bind($f, new A);print_r($a());//输出 103echo PHP_EOL;$b = Closure::bind($f, new B , 'B');print_r($b());//输出1003
In the above example, ##fthis人AnonymousName LetterNumber中 Mo名奇美ofThere is this, this The keyword indicates that this anonymous function needs to be bound in the class. After binding, it is as if there is such a function in A, but whether this function is public or private, the last parameter of bind indicates this function callable scope.
You have seen bindTo above, let’s take a look at the introduction on the official website
(PHP 5 >= 5.4.0, PHP 7)Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。 说明 public static Closure Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] ) 这个方法是 Closure::bindTo() 的静态版本。查看它的文档获取更多信息。 参数 closure 需要绑定的匿名函数。 newthis 需要绑定到匿名函数的对象,或者 NULL 创建未绑定的闭包。 newscope 想要绑定给闭包的类作用域,或者 'static' 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性。(备注:可以传入类名或类的实例,默认值是 'static', 表示不改变。)
FALSE
<?phpclass A {private static $sfoo = 1;private $ifoo = 2; }$cl1 = static function() {return A::$sfoo; };$cl2 = function() {return $this->ifoo; };$bcl1 = Closure::bind($cl1, null, 'A');$bcl2 = Closure::bind($cl2, new A(), 'A');echo $bcl1(), "\n";//输出 1echo $bcl2(), "\n";//输出 2
<?phpclass A {public $base = 100; }class B {private $base = 1000; }class C {private static $base = 10000; }$f = function () {return $this->base + 3; };$sf = static function() {return self::$base + 3; };$a = Closure::bind($f, new A);print_r($a());//这里输出103,绑定到A类echo PHP_EOL;$b = Closure::bind($f, new B , 'B');print_r($b());//这里输出1003,绑定到B类echo PHP_EOL;$c = $sf->bindTo(null, 'C'); //注意这里:使用变量#sf绑定到C类,默认第一个参数为nullprint_r($c());//这里输出10003
<?php/** * 复制一个闭包,绑定指定的$this对象和类作用域。 * * @author fantasy */class Animal {private static $cat = "加菲猫";private $dog = "汪汪队";public $pig = "猪猪侠"; }/* * 获取Animal类静态私有成员属性 */$cat = static function() {return Animal::$cat; };/* * 获取Animal实例私有成员属性 */$dog = function() {return $this->dog; };/* * 获取Animal实例公有成员属性 */$pig = function() {return $this->pig; };$bindCat = Closure::bind($cat, null, new Animal());// 给闭包绑定了Animal实例的作用域,但未给闭包绑定$this对象$bindDog = Closure::bind($dog, new Animal(), 'Animal');// 给闭包绑定了Animal类的作用域,同时将Animal实例对象作为$this对象绑定给闭包$bindPig = Closure::bind($pig, new Animal());// 将Animal实例对象作为$this对象绑定给闭包,保留闭包原有作用域echo $bindCat(),'<br>';// 输出:加菲猫,根据绑定规则,允许闭包通过作用域限定操作符获取Animal类静态私有成员属性echo $bindDog(),'<br>';// 输出:汪汪队, 根据绑定规则,允许闭包通过绑定的$this对象(Animal实例对象)获取Animal实例私有成员属性echo $bindPig(),'<br>';// 输出:猪猪侠, 根据绑定规则,允许闭包通过绑定的$this对象获取Animal实例公有成员属性
<?php/** * 给类动态添加新方法 * * @author fantasy */trait DynamicTrait {/** * 自动调用类中存在的方法 */public function __call($name, $args) {if(is_callable($this->$name)){return call_user_func($this->$name, $args); }else{throw new \RuntimeException("Method {$name} does not exist"); } }/** * 添加方法 */public function __set($name, $value) {$this->$name = is_callable($value)?$value->bindTo($this, $this):$value; } }/** * 只带属性不带方法动物类 * * @author fantasy */class Animal {use DynamicTrait;private $dog = '汪汪队'; }$animal = new Animal;// 往动物类实例中添加一个方法获取实例的私有属性$dog$animal->getdog = function() {return $this->dog; };echo $animal->getdog();//输出 汪汪队
<?php/** * 一个基本的购物车,包括一些已经添加的商品和每种商品的数量 * * @author fantasy */class Cart {// 定义商品价格const PRICE_BUTTER = 10.00;const PRICE_MILK = 30.33;const PRICE_EGGS = 80.88; protected $products = array();/** * 添加商品和数量 * * @access public * @param string 商品名称 * @param string 商品数量 */public function add($item, $quantity) {$this->products[$item] = $quantity; }/** * 获取单项商品数量 * * @access public * @param string 商品名称 */public function getQuantity($item) {return isset($this->products[$item]) ? $this->products[$item] : FALSE; }/** * 获取总价 * * @access public * @param string 税率 */public function getTotal($tax) {$total = 0.00;$callback = function ($quantity, $item) use ($tax, &$total) {$pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($item)); //调用以上对应的常量$total += ($pricePerItem * $quantity) * ($tax + 1.0); };array_walk($this->products, $callback);return round($total, 2); } }$my_cart = new Cart;// 往购物车里添加商品及对应数量$my_cart->add('butter', 10);$my_cart->add('milk', 3);$my_cart->add('eggs', 12);// 打出出总价格,其中有 3% 的销售税.echo $my_cart->getTotal(0.03);//输出 1196.4
Additional note: Closures can use the USE key to connect external variables.
Summary: The characteristics of PHP closures can actually achieve similar or even more powerful functions using CLASS, let alone the closures of js. We can only look forward to improvements in PHP's closure support in the future. However, anonymous functions are still quite useful. For example, when using functions such as preg_replace_callback, you don't need to declare a callback function externally. Proper use of closures can make code more concise and refined.
The above is the detailed content of Introduction to closure in php. For more information, please follow other related articles on the PHP Chinese website!