Passing in an anonymous function as a parameter in a common function can also be returned. This implements a simple closure.
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.
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:
'; // 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:
'; // 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:
'; // 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
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 ".
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.
Ifoo;}; $ bcl1 = Closure: bind ($ cl1, null, 'A'); $ bcl2 = Closure: bind ($ cl2, new (), 'A'); echo $ bcl1 (), "\ n"; // output 1 echo $ bcl2 (), "\ n"; // output 2
Let's take a look at an example to further understand:
Base + 3 ;}; $ sf = static function () {return self: $ base + 3 ;}; $ a = Closure: bind ($ f, new ); 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. The first parameter is nullprint_r ($ c () by default. // output 10003 here.
Let's look at another demo:
Dog ;};/** get the attributes of public members of an Animal instance */$ pig = function () {return $ this-> pig ;}; $ bindCat = Closure :: bind ($ cat, null, new Animal (); // bind 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, 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 echo $ bindCat (),'
'; // Output: Garfield. according to the binding rules, the closure is allowed to obtain the Animal static private member attribute echo $ bindDog (),' through the scope limitation operator (),'
'; // Output: Wang, according to the binding rules, allows the closure to obtain the private member attribute echo $ bindPig () of the Animal instance through the bound $ this object (Animal instance object (),'
'; // Output: PIG. according to the binding rules, the closure is allowed to obtain 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)
$ 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
Products [$ item] = $ quantity;}/*** obtain the quantity of a single item ** @ access public * @ param string item 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 is a summary of the details of the closure instance tutorial in php. For more information, see other related articles in the first PHP community!