11

I've recently started programming with PHP again, after a long stint with other languages during which i've developed a more functional style - which i'm hoping to try and maintain.

I've noticed some weird behaviour, which I managed to distill into a testcase that I'm hoping someone can explain.

$func = function($item) {
    if ($item == 0)
        throw new Exception("Can't do 0");
    return $item;
};

try {
    array_map($func, array(1, 2, 3, 0, 5));
} catch (Exception $ex) {
    echo "Couldn't map array";
}

When executing the above code, i see the following output:

Warning: array_map(): An error occurred while invoking the map callback in map_closure.php on line 10 Couldn't map array

I can suppress the error with @ on array_map, but this seems hacky at best.

hakre
  • 193,403
  • 52
  • 435
  • 836
Glenjamin
  • 7,150
  • 6
  • 25
  • 26
  • I am not sure if you are aware that the problem is with the Exception throwing? – AJJ Apr 02 '11 at 13:35
  • 2
    @AJweb; I think he wants to use exceptions for control flow, and wonders why he gets a warning from array_map. – falstro Apr 02 '11 at 13:40
  • @roe is correct, I *want* to throw an exception. I *very much do not want* the interpreter to dump some crap to stderr. – Glenjamin Apr 02 '11 at 14:22
  • 1
    For any arriving from Google etc. there's some more info here: https://bugs.php.net/bug.php?id=55416 – mbfisher Apr 22 '14 at 17:31
  • 1
    @Glenjamin If you don't want the interpreter to dump some crap to stderr, why do you think it is hacky to supress the dump with '@'. Normally I would agree with you, but if it's dump that PHP outputs in this case I would use `@`. And you aren't supressing errors. You throw an exception and you have a try-catch. For me it's not hacky... – algorhythm Oct 06 '14 at 13:38

4 Answers4

7

The warning is generated because, put simply, the callback function is not returning normally (due to throwing the Exception). This is just the way that array_map() is coded, if the callback function does not complete its execution. Remember an Exception breaks out of execution immediately, as far as your PHP code is concerned.

As for how to silence the warning, that's entirely up to you. Unfortunately, the warning will be generated and it's your choice to bury it or let it get displayed.

As an aside, maybe your test case was over-simplified but, it would make much more sense to use array_filter() (or perhaps array_reduce()) there.

salathe
  • 51,324
  • 12
  • 104
  • 132
  • 2
    Yeah, I vastly simplified things for the example code in this post, the original code was a nested PHPUnit loop, where the exception was raised to indicate test failure. – Glenjamin Apr 02 '11 at 14:21
  • @Glenjamin, as expected. What are your plans given the answers here? – salathe Apr 02 '11 at 14:22
  • I think my best option is to silence errors on array_map, and then make sure I throw exceptions for any error conditions inside the closures - which I intend to keep short. – Glenjamin Apr 02 '11 at 14:24
2

As preinhaimer says, array_map makes it really hard for you to see exactly what happened during its execution because it predates exceptions. It would not be practical to change its behavior anymore since that would lead to lots of (poorly-coded) applications breaking; that's life.

If you want a mechanism with which to check if the array_map completed without errors or not, I have posted a detailed answer (with code) to this question which deals with practically the same problem. It's not as easy as try/catch, but you work with what you have.

Community
  • 1
  • 1
Jon
  • 428,835
  • 81
  • 738
  • 806
1

Either use @ or a foreach instead of array_map

René Höhle
  • 26,716
  • 22
  • 73
  • 82
Gildas
  • 1,158
  • 1
  • 10
  • 25
0

array_map() predates exceptions so it still uses warnings. There's a few annoying places in PHP where you're still forced to use error handling, this is one of them.

You're left with options like having it return null or some other un-used value when it encounters a problem, or filtering the array to ensure it only contains valid options before you run it through array_map.

preinheimer
  • 3,712
  • 20
  • 34