Introducing closure usage examples in PHP

Source: Internet
Author: User
Tags stack trace
This article mainly introduces the closure usage in PHP, the need for friends can refer to the following

Closure, an anonymous function, is php5.3 when introduced, also known as anonymous functions. The literal meaning is that there is no function to define the name. For example, the following code (filename is do.php)

<?phpfunction A () {  return 100;}; function B (Closure $callback) {  return $callback ();} $a = B (A ());p rint_r ($a);//output: Fatal error:uncaught typeerror:argument 1 passed to B () must is an instance of Closure, int Eger given, called in D:\web\test\do.php on line one and defined in D:\web\test\do.php:6 Stack trace: #0 D:\web\test\do.php (one): B (+) #1 {main} thrown in D:\web\test\do.php on line 6?>

The A () here is never used as a parameter of B because it 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);p rint_r ($a);//output 100<? $func = function ($param) {  echo $param;}; $func (' Hello word ');//output: Hello Word

Implementing closures

The anonymous function is passed as a parameter in a normal function and can also be returned. This enables a simple closure.

Below I give three examples:

<?php//Example One//defines an anonymous function in a function and calls it function Printstr () {  $func = function ($str) {    echo $str;  };  $func (' Hello my girlfriend! ' );} Printstr ();//Output Hello my girlfriend!//Example II//return the anonymous function in the function and call it function Getprintstrfunc () {  $func = function ($str) {
  echo $str;  };  return $func;} $printStrFunc = Getprintstrfunc (); $printStrFunc (' Do I love me? ');//output Does you love me?//The anonymous function is passed as an argument, and it is called function Callfunc ($func) {  $func (' no!i hate you ');} $printStrFunc = function ($str) {  echo $str. ' <br> ';}; Callfunc ($printStrFunc);//You can also pass an anonymous function directly. If you know JS, this writing may be familiar with callfunc (function ($str) {  echo $str;//Output No!i hate you});

Keywords for connecting closures and external variables: use

Closures can hold some variables and values in the context of the code block. PHP by default, anonymous functions cannot invoke the context variables of the block of code, but need to use the Using keyword.

Let's take a look (OK, I'm short of money, I'm vulgar):


<?phpfunction Getmoney () {  $RMB = 1;  $dollar = 8;  $func = function () use ($RMB) {    echo $rmb;    echo $dollar;  };  $func ();} Getmoney ();//output: 1

As you can see, dollar is not declared in the Use keyword and is not available in this anonymous function, so be aware of this problem in development.

One might think that it is possible to change the context variables in an anonymous function, but I find that it seems to be impossible:


<?phpfunction Getmoney () {  $RMB = 1;  $func = function () use ($RMB) {    echo $rmb. ' <br> ';    Add the value of $RMB to 1    $RMB + +;  };  $func ();  echo $RMB;} Getmoney ();//output://1//1

Well, the original use reference is only a copy of the variable clone. But I want to fully reference the variable, not copy it? To achieve this effect, actually add a & symbol to the variable before it:

<?phpfunction Getmoney () {  $RMB = 1;  $func = function () use (& $RMB) {    echo $rmb. ' <br> ';    Add the value of $RMB to 1    $RMB + +;  };  $func ();  echo $RMB;} Getmoney ();//output://1//2

OK, so the anonymous function can refer to the variables of the context. If the anonymous function is returned to the outside world, the anonymous function will save the variables referenced by the use, and the outside world will not be able to get those variables, so the concept of a ' closure ' may be clearer.

According to the description we can change the above example:

<?phpfunction Getmoneyfunc () {  $RMB = 1;  $func = function () use (& $RMB) {    echo $rmb. ' <br> ';    Add the value of $RMB to 1    $RMB + +;  };  return $func;} $getMoney = Getmoneyfunc (); $getMoney (); $getMoney (); $getMoney ();//output://1//2//3

Okay, so much so, what if we're going to invoke an anonymous function inside a class? Direct on Demo

<?phpclass A {public  static function TestA () {    return function ($i) {//Returns an anonymous function return      $i +100;    };  }} function B (Closure $callback) {  return $callback (200);} $a = B (A::testa ());p rint_r ($a);//Output 300

One of the A::testa () returned is a nameless funciton.

The concept of binding

The above example of closure is just a global anonymous function, OK, so 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 rather a class of access.

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);p Rint_r ($a ());//output 103echo php_eol; $b = Closure::bind ($f, new B, ' B ');p Rint_r ($b ());//Output 100 3

In the example above, F, an anonymous function, has an inexplicable "this", which means that the anonymous function needs to be bound in the class.

After binding, it is as if there is such a function in a, but the function is public or the last parameter of Private,bind shows the callable scope of the function.

The above people saw bindto, we look at the official website introduction

(PHP 5 >= 5.4.0, PHP 7)

closure::bind-copy a closure that binds the specified $this object and class scope.

Description

public static Closure Closure::bind (Closure $closure, Object $newthis [, Mixed $newscope = ' static '])
This method is a static version of Closure::bindto (). View its documentation for more information.

Parameters

Closure

The anonymous function that needs to be bound.

Newthis

An object that is bound to an anonymous function, or NULL to create an unbound closure.

Newscope

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

return value:

Returns a new Closure object or FALSE on failure

<?phpclass A {  private static $sfoo = 1;  Private $ifoo = 2;} $CL 1 = static function () {  return A:: $sfoo;}; $CL 2 = function () {  return $this->ifoo;}; $BCL 1 = closure::bind ($CL 1, NULL, ' A '), $BCL 2 = Closure::bind ($cl 2, New A (), ' a '), echo $BCL 1 (), "\ n",//Output 1echo $BCL 2 (), "\ n ";//Output 2

Let's look at an example and deepen our understanding of:


<?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);p Rint_r ($a ());//Here Output 103, bind to Class A echo php_eol; $b = Closure::bind ($f, new B, ' B ');p Rint_r ($b ()) ;//Here Output 1003, bound to Class B echo php_eol; $c = $SF->bindto (null, ' C '); Note here: Use variable #sf to bind to Class C, the default first parameter is Nullprint_r ($c ());//Output here 10003

Let's look at another demo:

<?php/** * Copies a closure that binds the specified $this object and class scope. * * @author Fantasy */class Animal {  private static $cat = "Garfield";  Private $dog = "Barking Team";  Public $pig = "pig-Man";} /* Get Animal class static Private member Property */$cat = static function () {  return Animal:: $cat;};/ * * Get animal Instance Private member properties */$dog = function () {  return $this->dog;};/ * * Get animal Instance public member Properties */$pig = function () {  return $this->pig;}; $bindCat = Closure::bind ($cat, NULL, New Animal ());//The scope of the Animal instance is bound to the closure, but no $this object is bound to the closure $binddog = Closure::bind ($dog, New Animal (), ' Animal ');//Bind the scope of the Animal class to the closure, and bind the Animal instance object as a $this object to the closure $bindpig = Closure::bind ($pig, New Animal ()) ;//Bind the animal instance object as a $this object to the closure, preserving the original scope of the closure echo $bindCat (), ' <br> ';//output: Garfield, according to the binding rules, Allow closures to get the animal class static private member property via scoped operator Echo $bindDog (), ' <br> ';//output: Bark, allow closures to pass through the bound $this object (animal instance object), according to the binding rules Get animal Instance Private member properties Echo $bindPig (), ' <br> ';//output: Pig-man, allow closures to get animal instance public member properties by binding $this object based on binding rules

Through the above examples, in fact, the understanding of anonymous binding is not difficult .... We're looking at an extended demo (introducing the Trait feature)

<?php/** * Add a new method to the class dynamically * * @author fantasy */trait dynamictrait {  /**   * methods exist in the class automatically */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");    }  }  /**   * Add Method   *  /Public Function __set ($name, $value) {    $this-$name = is_callable ($value)?      $value->bindto ($this, $this):      $value;  }} /** * Only with attribute without method animal class * * @author fantasy */class Animal {use  dynamictrait;  Private $dog = ' barking team ';} $animal = new animal;//Adds a method to the animal instance to get the private property of the instance $dog$animal->getdog = function () {  return $this->dog;}; echo $animal->getdog ();//Output Barking Team

For example, now we use the shopping environment

<?php/** * A basic shopping cart, including some added items and the quantity of each item * * @author Fantasy */class Cart {//define commodity price const PRICE_BUTTER = 10.00;  Const PRICE_MILK = 30.33;   Const PRICE_EGGS = 80.88;  Protected $products = Array (); /** * Add goods and quantities * * @access public * @param string commodity name * @param string Commodity quantity */Public function Add ($item, $qua  ntity) {$this->products[$item] = $quantity; }/** * Get a single item quantity * * @access public * @param string commodity name */Public Function getquantity ($item) {return ISS ET ($this->products[$item])?  $this->products[$item]: FALSE;    }/** * Get Total Price * * @access public * @param string tax rate */Public Function gettotal ($tax) {$total = 0.00; $callback = function ($quantity, $item) use ($tax, & $total) {$pricePerItem = constant (__class__). "::P rice_". Strtoupper ($item));    Call the corresponding constants above $total + = ($pricePerItem * $quantity) * ($tax + 1.0);    };    Array_walk ($this->products, $callback);  Return round ($total, 2); }} $my _cart = nEW cart;//Add the goods and corresponding quantity $my_cart->add (' butter ') to the shopping cart, $my _cart->add (' Milk ', 3); $my _cart->add (' eggs ', 12);// Hit the total price, which has a sales tax of 3%. Echo $my _cart->gettotal (0.03);//Output 1196.4

Additional note: Closures can be used to connect external variables using the key.

Summary: The characteristics of PHP closures in fact, with class can achieve a similar or even much more powerful functions, and JS can not be compared with the closure of the bar, can only look forward to PHP after the improvement of the closure support. However, anonymous functions are useful, such as using functions such as preg_replace_callback and so on, without having to declare the callback function externally. Reasonable use of closures can make the code more concise and refined.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.