How can I use PHP 5.3 Closures like We use Blocks

2019-03-29 08:41发布

问题:

How can I use PHP 5.3 Closures like We use Blocks in Ruby. I never used 'for' Loop in Ruby due to using Blocks with 'each' 'find_all' 'inject' Methods.

How can I use PHP 5.3 Closures like Ruby Blocks and say bye-bye to 'for' Loops :)

Like Between { and } is a Closure(or Block or Anonymous Function)

fruit = %w[apple banana orange]
fruit.each { |f| print "#{f}, " }

I do it in PHP this way,

$fruit = array('apple', 'banana', 'orange');
foreach ($fruit as $f) 
{
 print "$f, "; 
}

Is there a way to do this the Ruby way using PHP Closures as PHP 5.3 supports it.

回答1:

If you are looking at using lambdas to iterate over a PHP array, there are certain functions that you could use to accomplish that. Better illustrate it, I used a wrapper class enum:

class enum {
    public $arr;

    function __construct($array) {
        $this->arr = $array;
    }

    function each($lambda) {
        array_walk($this->arr, $lambda);
    }

    function find_all($lambda) {
        return array_filter($this->arr, $lambda);
    }

    function inject($lambda, $initial=null) {
        if ($initial == null) {
            $first = array_shift($this->arr);
            $result = array_reduce($this->arr, $lambda, $first);
            array_unshift($this->arr, $first);

            return $result;
        } else {
            return array_reduce($this->arr, $lambda, $initial);
        }
    }

}


$list = new enum(array(-1, 3, 4, 5, -7));
$list->each(function($a) { print $a . "\n";});

// in PHP you can also assign a closure to a variable 
$pos = function($a) { return ($a < 0) ? false : true;};
$positives = $list->find_all($pos);

// inject() examples
$list = new enum(range(5, 10));

$sum = $list->inject(function($sum, $n) { return $sum+$n; });
$product = $list->inject(function($acc, $n) { return $acc*$n; }, 1);

$list = new enum(array('cat', 'sheep', 'bear'));
$longest = $list->inject(function($memo, $word) {
        return (strlen($memo) > strlen($word)) ? $memo : $word; }
    );

That being said, closures in PHP aren't meant to replace the for loop nor do they behave like ruby blocks.



回答2:

I think array_map() and array_walk() look better as RubyBlocks replacement.



回答3:

I don't think an anonymous function is a substitute for a for loop, nor do I think it's necessary to replace for loops with them.

What it is useful for is a callback. Take this for example: (yes, it is a lame bubble sort, but it is an example)

<?php

function bubble_sort($sort_rule, $elements) {
    do {
        $swapped = false;
        for ($i = 0; $i < count($elements) - 1; $i++) {
            if ($sort_rule($elements[$i], $elements[$i + 1])) {
                $elements[$i] ^= $elements[$i + 1];
                $elements[$i + 1] ^= $elements[$i];
                $elements[$i] ^= $elements[$i + 1];
                $swapped = true;
            }
        }
    } while($swapped);
    return $elements;
}

print_r(bubble_sort(function ($a, $b) { if ($a > $b) return true; else return false; }
,array(1,6,3,7,42,-1,0,6)));
?>

Closures aren't a replacement for for loops in a procedural programming language like php. Sure if you're using lisp or scheme they are, but that's out of necessity.

You can write them that way, all you'll really be doing is creating an anonymous function with a for loop inside it. I think recursion would just be unnecessary if the task is just as easily accomplished with a for loop, and therefore you're not kissing for loops good bye.

Anonymous functions are very useful in event driven programming as well, when you want to just define a callback method really quick.



回答4:

Simple answer: you don't. Ruby is not devoid of for() loops, they just mask the word "for" and change the syntax a bit. If you wanted to use a closure, it'd just be a closure with a loop inside it, or an ugly (and less efficient) recursive closure.

And closures are NOT the same thing as blocks. Closures are comparable to functions in JavaScript-- that is, they can be stored in variables and sent as arguments.