I'm beginning to wonder what that actual point of fat arrow functions in PHP really are. With the exception of multi-line logic, I figured they basically worked the same way they do in JavaScript, giving you full, direct access to the parent scope. But, that is clearly not how they work!
In JavaScript if you use the arrow function syntax you get direct access to the outer scope - SUPER handy! So in JS I might do something like this:
const foo = [1,2,3,4]
const bar = ['one', 'two', 'three', 'four']
const baz = bar.flatMap((i) => [foo.shift(), i])
// baz === [1, 'one', 2, 'two', 3, 'three', 4, 'four']
With the arrow function syntax I can access foo
an it works as expected, giving me the first item from the array on each iteration.
In PHP, if I try the same:
$foo = [1,2,3,4];
$bar = ['one', 'two', 'three', 'four'];
// Using Laravel's collect for simplicity here:
$baz = collect($foo)
->flatMap(fn ($i) => [array_shift($foo), $i])
->toArray();
// $baz === [1, 'one', 1, 'two', 1, 'three', 1, 'four']
PHP gives me access to the outer scope with a fat arrow function, so I don't have to explicitly pass variables into my closure, which is nice, but.. they don't work the way I expect. I'm sure there's a good PHP internals reason for this, and the best I can figure is that fat arrows are just syntactic sugar for a function that simply returns whatever is after the arrow, and makes all the things available as if you manually passed everything in a use ()
, but it clearly does so by COPY not by REFERENCE...
Because even if I use the more verbose closure syntax:
$foo = [1,2,3,4];
$bar = ['one', 'two', 'three', 'four'];
// Using Laravel's collect for simplicity here:
$baz = collect($foo)
->flatMap(function ($i) use ($foo) {
return [array_shift($foo), $i];
})
->toArray();
// $baz === [1, 'one', 1, 'two', 1, 'three', 1, 'four']
I get the same thing. I have to specifically use the more verbose closure syntax and explicitly pass my $foo
array into the closure by reference:
$foo = [1,2,3,4];
$bar = ['one', 'two', 'three', 'four'];
// Using Laravel's collect for simplicity here:
$baz = collect($foo)
->flatMap(function ($i) use (&$foo) {
return [array_shift($foo), $i];
})
->toArray();
// $baz === [1, 'one', 2, 'two', 3, 'three', 4, 'four']
This again, kind of feels unnecessary, because array_shift()
explicitly accepts the array you pass into it by reference ... so one, like myself, might logically conclude that it should behave the way the JS version does.
Best I can figure is that in a closure, whatever you pass in, is passed by COPY on every iteration, unless you've explicitly passed it in by REFERENCE – and there's no way to DO THAT in a fat arrow function. 🤬
This leaves me wondering, truly, wtf is the actual point of fat arrow functions in PHP? They don't really seem to give that much value, other than slightly less verbosity - which, granted, is often a good thing.. but the lack of being able to do multiple lines, a la:
let foo = (bar) => {
//do some stuff
// do some other stuff
return 'something'
};
...and apparently only giving restrictive access to the parent scope... what's the point?