A brief discussion on the practical application of PHP closure feature

  • 2020-03-31 16:46:28
  • OfStack

Well, for the most part it does, but for the most part it can be very confusing.
Many languages provide very elegant and beautiful methods for manipulating arrays. In the following examples, closures provided by PHP5.3 and other languages are used to show how to iterate over arrays "objectively."
I don't know the language Groovy or Scala, so I'll add the Javascript implementation here.
Before we start, this example is just to clarify the point, and does not consider other aspects such as performance.

"Shop around"

To start with a simple example, here's an array:
$nums = array(10, 20, 30, 40); We need to find the items in the array that are greater than 15. So, without considering closures, we might write:
$res = array (); Foreach ($nums as $n) {if ($n > 15) {$res[] = $n; }} if the language itself had closure support, this might be written (Groovy language)
Def res = nums.findAll {it > 15} or the Scala language
Val res = nums filter (_ > Javascript 1.6 would look like this
Var res = nums.filter(function(c){return c > 15}); Because the loop has been abstracted, you can see that Groovy, Scala (and Javascript) are all beautiful and can be done in one line.
Of course, you can do the same if you use the closure of PHP5.3
$res = array_filter($nums, function($v) {return $v > 15. }); PHP USES more characters in this respect than Scala, but it's shorter and easier to read than the previous examples.

By the way, the above PHP code actually USES a Lambda parser and is not really a closure, which is not our focus right now. See here for details on PHP closures and Lambda parsers.
So it looks good so far, so let's make it a little bit harder: find all the terms that are greater than 15, multiply them by 2 plus some variable in scope and return them later.

Implementation of Groovy:
Def x = 1def res = nums. findAll {it > 15}. Collect {it * 2 + x}Scala implementation:
Val x = 1val res = nums filter (_ > 15) map (_ * 2 + x)
Var I = 1; Var res = nums.filter(function(c){return c > Function (c){return c * 2 + I}); And PHP:
$x = 1; $res = array_map(function($v) use ($x) {return $v * 2 + $x; }, array_filter($nums, function($v) {return $v > 15. })); In terms of the amount of code, PHP now looks different from other languages. Leaving aside the aesthetics of the code itself, the above PHP code has an additional problem.
For example, what if you need to use the keys of an array instead of the values for comparison? Yes, the code above does not. Also, syntactically, the above code is very difficult to read.

To get back to basics, you still have to go back to your old ways to solve the problem:
$x = 1; $res = array (); Foreach ($nums as $n) {if ($n > 15) {$res[] = $n * 2 + $x; }}, so it looks clear again. At this point, however, you might be wondering, "what's the point? It's just an array operation." .
Yes, the best is yet to come. It's time to introduce some of the more advanced features of PHP to tackle this seemingly self-destructive "boredom problem."

ArrayObject wok encapsulation of array
PHP has a standard library called SPL that contains a class called ArrayObject that provides "array-like action classes," for example
$res = new ArrayObject(array(10, 20, 30, 40)); Foreach ($res as $v) {echo "$vn"; }ArrayObject is a built-in class, so you can encapsulate it just like any other class class operation.

Arr - sugar coated

Now that we have features like ArrayObject and closures, we can start trying to wrap it:
Class Arr extends ArrayObject{static function make($array) {return new self($array); Function map($func) {$res = new self(); Foreach ($this as $k => $v) {$res[$k] = $func($k, $v); } return $res; Function filter($func) {$res = new self(); Foreach ($this as $k => $v) {if ($func($k, $v)) {$res[$k] = $v; }} return $res; All right, everything is ready. The following rewrite of the PHP code solves the above problem and looks syntactically "close" :

$res = Arr: : make ($nums) - > Filter (function($k, $v) {return $v > 15. }) - > Function ($k, $v) {return $v * 2; }); How does the above code differ from the traditional approach? First, they can be recursive and form a chain of calls, so more similar operations can be added.

At the same time, the two parameters of the callback can be used to manipulate the key and value of the array, respectively - $k corresponding key and $v corresponding value. This allows us to use key values in closures, which is not possible with the traditional PHP function array_fliter.
Another added benefit is more consistent API calls. Using traditional PHP functions, they might take a closure as the first argument, or an array, or multiple arrays... Anyway, who knows?
Here is the complete source code for the Arr class, which also contains other useful functions (like reduce and walk) that are implemented in a similar way to the code.

game

This is a difficult question to answer - it depends on the context of the code and the programmer himself. In fact, when I first saw the implementation of closures in PHP, it felt like a throwback to the days of Java, when I started using anonymous inner classes to implement closures. Sure, it can be done, but it seems like a lot of gilding a lily. The PHP closure itself is correct, but the implementation and syntax are confusing.
Other languages have closure features that make it easy to invoke closures with elegant syntax. In the above example, a traditional loop would work in Scala, but would you write it that way? On the other hand, someone said that the above topic could be implemented using PHP closures, but would you normally write that?
Sure, PHP closures can be sharp sabers in some situations (such as delayed execution and resource calls), but they can be a bit of a pain in the traditional iterative and array operations. No matter what, it's important to get back to basics and write compatible, clean code and apis.

conclusion

Like all the syntax features added later (remember the Generics feature in Java? PHP OOP features from previous years), both of which take time to grind in and eventually stabilize. With the popularity of PHP5.3 and even the future of PHP6, more and more skills and features are believed to be developed by smart programmers in the near future.
Go back to the title at the beginning of the original article and compare
$res = Arr: : make ($nums) - > Filter (function($k, $v) {return $v > 15. }) - > Function ($k, $v) {return $v * 2; }); As well as
Val res = nums filter (_ > 15) the difference between map (_ * 2) and map (_ * 2). In the final analysis, they are only grammars, which are essentially the same solution to the same problem. The application characteristics of programming languages are different, so there is no way to compare them.
Finally, here are code examples for this article, and I'm sure you can find out more about how to use PHP for functional iteration (and not just that).

Unreliable bloggers get what they want
To be honest, even though you've seen the proposed new closures and other features before PHP5.0, when you see the closures and Lambda features provided by PHP5.3, it's not quite what you'd expect.
Even in contrast to the familiar JavaScript, PHP closures seem to me to be a product of the "other languages have them, so I'll have them too" mentality.

However, as mentioned above, PHP is different from other development languages for its own application and implementation philosophy, compared with other dynamic languages such as JavaScript.

Therefore, some features will be invoked in different ways and implementation methods, which will inevitably make people familiar with another language with similar functions feel uncomfortable.

Since the launch of PHP5.3, it has been less than half a year. Compared with JavaScript and other dynamic languages with features such as closures, it is natural that they are very immature.

At the same time, most developers are still waiting to see what new features PHP5.3 offers, including closures. PHP's closure features still exist in the lab, and they have been applied to practical development to break through not only the language features, but also the efficiency, security and other aspects of the test.
But I believe, as the authors of the original article said, that as the PHP version progresses, PHP closures will be used more and more frequently. Like the conversion from PHP4 to PHP5, the adaptation to the new features of the language is actually a painful and happy process.

Related articles: