Home > Database > Mysql Tutorial > body text

Detailed explanation of closure usage examples in php

怪我咯
Release: 2017-07-11 15:46:32
Original
1438 people have browsed it

Closure, Anonymous functions, also known as Anonymous functions, were introduced in php5.3. An anonymous function is a function without a defined name, that is, a closure. Keep this in mind to understand the definition of an anonymous function. For example, the following code (the file name is do.php)

<?php
function 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
?>
Copy after login

here A() 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( &#39;hello word&#39; );
//输出:hello word
Copy after login

implementation. Closure##Pass anonymous functions as parameters in ordinary functions, and they can also be returned. This implements a simple closure.

I will give you an example below. Three examples:

<?php
//例一
//在函数里定义一个匿名函数,并且调用它
function printStr() {
  $func = function( $str ) {
    echo $str;
  };
  $func( &#39; hello my girlfriend ! &#39; );
}
printStr();//输出 hello my girlfriend !
//例二
//在函数中把匿名函数返回,并且调用它
function getPrintStrFunc() {
  $func = function( $str ) {
    echo $str;
  };
  return $func;
}
$printStrFunc = getPrintStrFunc();
$printStrFunc( &#39; do you love me ? &#39; );//输出 do you love me ?
//例三
//把匿名函数当做参数传递,并且调用它
function callFunc( $func ) {
  $func( &#39; no!i hate you &#39; );
}
$printStrFunc = function( $str ) {
  echo $str.&#39;<br>&#39;;
};
callFunc( $printStrFunc );
//也可以直接将匿名函数进行传递。如果你了解js,这种写法可能会很熟悉
callFunc( function( $str ) {
  echo $str; //输出no!i hate you
} );
Copy after login

Keywords that connect closures and external variables: USE

Closures can save some variables and values ​​​​in the context of the code block in which PHP uses anonymous functions by default. The context variable of the code block cannot be called, but you need to use the use keyword

Let’s take a look at another example (ok, I’m short of money, I’m vulgar):

<?php
function getMoney() {
  $rmb = 1;
  $dollar = 8;
  $func = function() use ( $rmb ) {
    echo $rmb;
    echo $dollar;
  };
  $func();
}
getMoney();
//输出:1
Copy after login

You can see it. Note that dollar is not declared in the use keyword, so it cannot be obtained in this anonymous function, so we should pay attention to this issue during development.

Some people may wonder whether the context can be changed in the anonymous function. variable, but I found that it seems not possible:

<?php
function getMoney() {
  $rmb = 1;
  $func = function() use ( $rmb ) {
    echo $rmb.&#39;<br>&#39;;
    //把$rmb的值加1
    $rmb++;
  };
  $func();
  echo $rmb;
}
getMoney();
//输出:
//1
//1
Copy after login

Well, it turns out that use refers to only a copy of the variable, but what if I want to fully reference the variable instead of copying it? To achieve this effect, just add an & symbol before the variable:

<?php
function getMoney() {
  $rmb = 1;
  $func = function() use ( &$rmb ) {
    echo $rmb.&#39;<br>&#39;;
    //把$rmb的值加1
    $rmb++;
  };
  $func();
  echo $rmb;
}
getMoney();
//输出:
//1
//2
Copy after login

Okay, so that the anonymous function can reference the context variable. If the anonymous function is returned to the outside world, the anonymous function will save it. The variables referenced by use cannot be obtained by the outside world, so the concept of 'closure' may be clearer

Let's change the above example based on the description:

<?php
function getMoneyFunc() {
  $rmb = 1;
  $func = function() use ( &$rmb ) {
    echo $rmb.&#39;<br>&#39;;
    //把$rmb的值加1
    $rmb++;
  };
  return $func;
}
$getMoney = getMoneyFunc();
$getMoney();
$getMoney();
$getMoney();
//输出:
//1
//2
//3
Copy after login

Okay, so much, what if we want to call an anonymous function in a class? Go directly to the demo

<?php
class 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
Copy after login

A::testA() returns an unnamed funciton

.

The concept of binding

The Closure in the above example is just a global anonymous function. Okay, now we want to specify that a class has an anonymous function. 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. .

<?php
class A {
  public $base = 100;
}
class B {
  private $base = 1000;
}
$f = function () {
  return $this->base + 3;
};
$a = Closure::bind($f, new A);
print_r($a());//输出 103
echo PHP_EOL;
$b = Closure::bind($f, new B , &#39;B&#39;);
print_r($b());//输出1003
Copy after login

In the above example, the anonymous function f has this inexplicably. This keyword means that the anonymous function needs to be bound to the class.

Binding. After it is determined, 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 the callable scope of this function.

You have seen bindTo above, let’s take a look at the introduction on the official website

(PHP 5 >= 5.4.0, PHP 7)
Copy after login

Closure::bind — Copy a closure and bind the specified $this object and class scope.

Description

public static Closure Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = 'static' ] )

This method is

Closure: Static version of :bindTo

(). Check out its documentation for more information.

Parameters
closure

Anonymous function that needs to be bound.

newthis

Requires an object bound to an anonymous function, or NULL to create an unbound closure.

newscope

The class scope you want to bind to the closure, or 'static' means no change. If an object is passed in, the type name of the object is used. Class scope is used to determine the visibility of private, protected methods of the $this object within the closure. (Note: You can pass in the class name or an instance of the class. The default value is 'static', which means no change.)

Return value:

Return a new Closure object or on failure Return FALSE

<?php
class A {
  private static $sfoo = 1;
  private $ifoo = 2;
}
$cl1 = static function() {
  return A::$sfoo;
};
$cl2 = function() {
  return $this->ifoo;
};
$bcl1 = Closure::bind($cl1, null, &#39;A&#39;);
$bcl2 = Closure::bind($cl2, new A(), &#39;A&#39;);
echo $bcl1(), "\n";//输出 1
echo $bcl2(), "\n";//输出 2
Copy after login

Let’s look at an example to deepen our understanding:

<?php
class 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 , &#39;B&#39;);
print_r($b());//这里输出1003,绑定到B类
echo PHP_EOL;
$c = $sf->bindTo(null, &#39;C&#39;); //注意这里:使用变量#sf绑定到C类,默认第一个参数为null
print_r($c());//这里输出10003
Copy after login

Let’s look at a demo again:

<?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(), &#39;Animal&#39;);// 给闭包绑定了Animal类的作用域,同时将Animal实例对象作为$this对象绑定给闭包
$bindPig = Closure::bind($pig, new Animal());// 将Animal实例对象作为$this对象绑定给闭包,保留闭包原有作用域
echo $bindCat(),&#39;<br>&#39;;// 输出:加菲猫,根据绑定规则,允许闭包通过作用域限定操作符获取Animal类静态私有成员属性
echo $bindDog(),&#39;<br>&#39;;// 输出:汪汪队, 根据绑定规则,允许闭包通过绑定的$this对象(Animal实例对象)获取Animal实例私有成员属性
echo $bindPig(),&#39;<br>&#39;;// 输出:猪猪侠, 根据绑定规则,允许闭包通过绑定的$this对象获取Animal实例公有成员属性
Copy after login

Through the above examples, in fact, anonymous binding It’s not difficult to understand.... We are looking at an extended demo (introducing trait features)

<?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 = &#39;汪汪队&#39;;
}
$animal = new Animal;
// 往动物类实例中添加一个方法获取实例的私有属性$dog
$animal->getdog = function() {
  return $this->dog;
};
echo $animal->getdog();//输出 汪汪队
Copy after login

For example, now we use the current shopping environment

<?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(&#39;butter&#39;, 10);
$my_cart->add(&#39;milk&#39;, 3);
$my_cart->add(&#39;eggs&#39;, 12);
// 打出出总价格,其中有 3% 的销售税.
echo $my_cart->getTotal(0.03);//输出 1196.4
Copy after login
Additional explanation: Closures can use USE Key connects external variables.

Summary: The characteristics of PHP closures can actually be used to achieve similar or even more powerful functions using CLASS, let alone the closures of js. I can only look forward to PHP's future

Closure support

improvements. However, anonymous functions are still quite useful. For example, when using functions such as preg_replace_callback, you don't need to declare the
callback function

externally. Proper use of closures can make code more concise and refined.

The above is the detailed content of Detailed explanation of closure usage examples in php. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!