Search code examples
phploopslanguage-agnosticprogramming-languages

indexed array foreach shorthand


Data:

$players = array(
    new Player('psycketom'),
    new Player('stackexchanger'),
    new Player('max')
);

Usually, in order to get something out of every object within array, we have to use / .

foreach ($players as $player)
{
    var_dump( $player->score );
}

But, since it's a repetitive task, is there a way to shortcut it to something along these imaginary lines(?):

var_dump( every( $players )->score );

every( $players )->score += 40;

Since I have not seen such a feature for , is there a way to implement it?

I have asked the question using as main language, but the and stand for the second part of the question: what languages support such or at least similar shorthand?


Solution

  • So, you are correct that PHP does not support this "out of the box" (except kinda, see below). The first language I know of that does is Objective-C (well, at least the CoreFoundation library). NSArrays and other sets have methods to (in one line) instruct that a given method should be executed on all members; and even more cool (to me, at least) is the concept of "keypaths" and the support that NSArray and others has for them. An example; lets say you have an array of "people" who each have a parent, who in turn have a "name":

    arrayOfNames = [peopleArray valueForKeyPath:"parent.name"];
    

    arrayOfNames is now an array of all the parents' names.

    The closest thing PHP has is array_map, which you can use together with anonymous functions to very quickly whip something together.

    edit anecdotal as it may be, one should remember that loop structures don't need their curly-braces if there is only one statement to execute; so any fancier solutions need to compete with this:

    foreach($players as $p) $p->score += 40;
    

    And I'll mention a deeper solution for those OOP fans out there... If you work with collection objects instead of arrays, the world is your oyster with stuff like this. The simplest concept that comes to mind is php's magic __call() method. How simple to iterate over your members and make that call for your users? For more controll, you can implement a few different strategies for iteration (one for transforms, one for filters, etc. Difference being what gets returned, essentially). So in theory you could create a few different iterator classes, and in your "main" collection class implement a couple methods to get one of them, which will be pre-initialized with the contents:

    $players->transform()->addScore(40);
    

    where transform() returns an instance of your "don't return the array" iterator, which uses the __call() technique.

    The sky starts to open up at this point, and you can start to build filter iterators which take predicates and return another collection of a subset of the objects, and syntax like this is possible:

    // send flyer to all parents with valid email address
    $parentsPredicate = new Predicate('email');
    $players->filteredByPredicate($parentsPredicate)->each()->email($fyler_email_body);