Details on closure usage in php and phpclosure usage

Source: Internet
Author: User

Details on closure usage in php and phpclosure usage

Closure, an Anonymous function, was introduced in php5.3, also known as Anonymous functions. That is, a function with no name defined. For example, the following code (the file name is do. php)

<? Phpfunction A () {return 100 ;}; function B (Closure $ callback) {return $ callback () ;}$ a = B (()); print_r ($ a); // output: 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?>

Here, A () can never be used as the parameter of B, because A is not an "anonymous" function.

So we should change it to this:

<? Php $ f = function () {return 100;}; function B (Closure $ callback) {return $ callback () ;}$ a = B ($ f ); print_r ($ a); // output 100 <? $ Func = function ($ param) {echo $ param;}; $ func ('Hello word'); // output: hello word

Implement closures

Passing in an anonymous function as a parameter in a common function can also be returned. This implements a simple closure.

Here are three examples:

<? Php // Example 1 // define an anonymous function in the function and call the function printStr () {$ func = function ($ str) {echo $ str ;}; $ func ('Hello my girlfriend! ');} PrintStr (); // output hello my girlfriend! // Example 2 // return the anonymous function in the function and call it function getPrintStrFunc () {$ func = function ($ str) {echo $ str ;}; return $ func;} $ printStrFunc = getPrintStrFunc (); $ printStrFunc ('Do you love me? '); // Output do you love me? // Example 3 // pass the anonymous function as a parameter and call its function callFunc ($ func) {$ func ('No! I hate you ');} $ printStrFunc = function ($ str) {echo $ str. '<br>' ;}; callFunc ($ printStrFunc); // You can also pass anonymous functions directly. If you know about js, you may be familiar with callFunc (function ($ str) {echo $ str; // output no! I hate you });

Keyword for connecting closure and external variables: USE

The closure can save some variables and values in the context of the code block. By default, an anonymous function cannot call the context variable of the code block, but must use the use keyword.

Let's look at another example (well, I am short of money, I am 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 cannot be obtained in this anonymous function. Therefore, pay attention to this issue during development.

Some people may think about whether the context variables can be changed in anonymous functions, but I find it is not possible:

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

The original use references only a copy of the variable clone. But what if I want to completely reference the variable instead of copying it? To achieve this effect, you can add an & symbol before the variable:

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

Okay, so that the anonymous function can reference the context variable. If an anonymous function is returned to the outside world, the anonymous function will save the variables referenced by use, and the outside world will not be able to get these variables, so that the concept of 'closures 'may be clearer.

Based on the description, let's change the above example:

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

Okay, 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) {// returns the anonymous function return $ I + 100 ;}} function B (Closure $ callback) {return $ callback (200) ;}$ a = B (A: testA (); print_r ($ a); // output 300

Among them, A: testA () returns an unknown funciton.

Concept of binding

The Closure in the above example is only a global anonymous function. Well, now we want to specify a class with an anonymous function. It can also be understood that the access range of this anonymous function is no longer global, but the access range 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 (); // output 103 echo PHP_EOL; $ B = Closure :: bind ($ f, new B, 'B'); print_r ($ B (); // output 1003

In the above example, the anonymous function f contains this inexplicably. this keyword indicates that the anonymous function needs to be bound to the class.

After binding, it is like A has such A function, but the function is public or private. The last parameter of bind shows the callable range of the function.

We 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-copy a Closure and bind it to the specified $ this object and Class scope.

Description

Public static Closure: bind (Closure $ closure, object $ newthis [, mixed $ newscope = 'static '])
This method is the static version of Closure: bindTo. View its documentation for more information.

Parameters

Closure

The anonymous function to be bound.

Newthis

The object to be bound to an anonymous function, or NULL creates an unbound closure.

Newscope

The class scope that you want to bind to the closure, or 'static 'indicates that it will not change. If an object is input, the type name of the object is used. The class scope is used to determine the visibility of the $ this object in the closure and the protection method. (Note: You can input an instance of the class name or class. The default value is 'static ', indicating that the instance will not be changed .)

Return Value:

Returns a new Closure object or FALSE if the object fails.

<? 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"; // output 1 echo $ bcl2 (), "\ n"; // output 2

Let's take a look at an example to further understand:

<? 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 (); // output 103, bound to echo PHP_EOL of Class A; $ B = Closure :: bind ($ f, new B, 'B'); print_r ($ B (); // output 1003, bound to echo PHP_EOL of Class B; $ c = $ sf-> bindTo (null, 'C'); // Note: use variable # sf to bind to Class C, by default, the first parameter is nullprint_r ($ c (); // output 10003

Let's look at another demo:

<? Php/*** copies a closure and binds the specified $ this object and Class scope. ** @ Author fantasy */class Animal {private static $ cat = "Garfield"; private $ dog = "Wang"; public $ pig = "";} /** get static private member attributes of the Animal class */$ cat = static function () {return Animal: $ cat ;}; /** obtain the attributes of Private Members of an Animal instance */$ dog = function () {return $ this-> dog ;}; /** get attributes of public members of an Animal instance */$ pig = function () {return $ this-> pig;}; $ bindCat = Closure: bind ($ cat, null, new Animal (); // bound the Animal instance scope to the Closure, but not to the Closure $ this object $ bindDog = Closure: bind ($ dog, new Animal (), 'animal '); // bind the Animal class scope to the Closure, and bind the Animal instance object as the $ this object to the Closure $ bindPig = Closure: bind ($ pig, new Animal (); // bind the Animal instance object to the closure as the $ this object, and keep the original scope echo $ bindCat (), '<br>' of the closure; // output: garfield, according to the binding rules, allows the closure to obtain the Animal static private member attribute echo $ bindDog (), '<br>' through the scope limitation operator; // output: Wang, according to the binding rules, the closure is allowed to obtain the private member attribute echo $ bindPig (), '<br>' through the bound $ this object (Animal Instance Object); // output: pig, according to the binding rules, allows the closure to get the public member attribute of the Animal instance through the bound $ this object

Through the above examples, it is not difficult to understand anonymous binding... we are looking at an extended demo (introducing the trait feature)

<? Php/*** Add a new method to the class dynamically ** @ author fantasy */trait DynamicTrait {/*** automatically call methods in the class */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 attributes without METHOD Animal classes ** @ author fantasy */class animal {use DynamicTrait; private $ dog = 'wangwang team';} $ Animal = new Animal; // Add a method to the animal instance to obtain the private attribute of the Instance $ dog $ animal-> getdog = function () {return $ this-> dog ;}; echo $ animal-> getdog (); // output Wangwang

For example, now we use the current shopping environment

<? Php/*** a basic shopping cart, include some added items and the quantity of each item ** @ author fantasy */class Cart {// define the product price const PRICE_BUTTER = 10.00; const PRICE_MILK = 30.33; const PRICE_EGGS = 80.88; protected $ products = array (); /*** add item and quantity ** @ access public * @ param string item name * @ param string item quantity */public function add ($ item, $ quantity) {$ this-> products [$ item] = $ quantity;}/*** obtain the number of individual items ** @ access public * @ param string Operator Product name */public function getQuantity ($ item) {return isset ($ this-> products [$ item])? $ This-> products [$ item]: FALSE;}/*** get the 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 __. ": PRICE _". strtoupper ($ item); // call the above constant $ total + = ($ pricePerItem * $ quantity) * ($ tax + 1.0 );}; array_walk ($ this-> products, $ callback); return round ($ total, 2) ;}$ my_cart = new Cart; // add the product and quantity to the shopping cart $ my_cart-> add ('butter ', 10); $ my_cart-> add ('milk', 3 ); $ my_cart-> add ('eggs', 12); // you can obtain the total price, with a sales tax of 3%. echo $ my_cart-> getTotal (0.03); // output 1196.4

Note: The closure can USE the USE key to connect external variables.

Summary: The features of PHP closures can actually implement similar or even more powerful functions using CLASS. It cannot be compared with the closure of js. We can only look forward to improving the closure support of PHP in the future. However, anonymous functions are quite useful. For example, if you use functions such as preg_replace_callback, you do not need to declare callback functions externally. The rational use of closures makes the code more concise and refined.

The above section describes how to use closure in php. I hope it will be helpful to you. If you have any questions, please leave a message and I will reply to you in a timely manner. Thank you very much for your support for the help House website!

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.