0

I am not sure how to increase my email_actions in this snippet:

$email_actions = 0;
array_walk(
    $steps,
    fn($step): int => !empty($step['settings']['type']) &&
                      $step['settings']['type'] === self::FLOWS_EMAIL_TYPE_ACTION
                          ? $email_actions++
                          : false
);
dd($email_actions);

I get 0 as result when it should be 2. Tried to pass the variable by reference like: fn($step, &$email_actions) but is obviously not the right approach.

6
  • Never tried with arrow functions but I think it needs to be fn($step) use (&$email_actions) : int =>? Commented Sep 19, 2022 at 11:11
  • @nice_dev Tried this one as well. Didn't work. In fact i really don't see and option to do it with fn. Commented Sep 19, 2022 at 11:15
  • 1
    @nice_dev fn() is supposed to bring the outer variables. fn($foo) => $foo + $bar; is equivalent to function($foo) use ($bar) { ... } Commented Sep 19, 2022 at 11:16
  • I'd never understand why use array_walk where a simple foreach would do. Given you have a hard time understanding how this code works right now means you will have absolutely no idea on that in a couple months. Why someone would voluntarily obfuscate their own code is beyond my understanding Commented Sep 19, 2022 at 11:24
  • 1
    @TomaTomov To answer your question, it ain't possible. Looks like we need to write an email to NikiC :p Commented Sep 19, 2022 at 13:32

3 Answers 3

1

fn copies the variables that are automatically injected.

From documentation (check example 4) :

Arrow functions use by-value variable binding. This is roughly equivalent to performing a use($x) for every variable $x used inside the arrow function. A by-value binding means that it is not possible to modify any values from the outer scope. Anonymous functions can be used instead for by-ref bindings.

If you want to have a write access (a reference), you might need to use the old syntax :

$email_actions = 0;
array_walk(
    $steps,
    function($step) use (&$email_actions) : int
    {
        return !empty($step['settings']['type']) &&
               $step['settings']['type'] === self::FLOWS_EMAIL_TYPE_ACTION
                   ? $email_actions++
                   : false;
    }
);
dd($email_actions);
Sign up to request clarification or add additional context in comments.

Comments

1

You should be using array_reduce to get single value after iterating through all array

$email_actions = array_reduce(
    $steps,
    function ($carry, $step) {
        if ($step['settings']['type'] === self::FLOWS_EMAIL_TYPE_ACTION) {
            $carry++;
        }
        
        return $carry;
    },
    0
);


If you really need to use arrow functions:

$email_actions = array_count(
    array_filter($steps, fn ($step) => $step['settings']['type'] === self::FLOWS_EMAIL_TYPE_ACTION)
);

3 Comments

It is about the fn syntax mostly. How can I use reference with it.
@TomaTomov You can't do that with arrow functions, does not seem like you are using functions as they are intended to be used.
@TomaTomov Check updated answer with use of arrow function. But you still can't modify outside scope variables.
1

When using functional-style array traversal to return anything other than an array of equal size, array_reduce() is most appropriate. Arrow syntax becomes more enjoyable when global scope referencing is no longer needed. Demo

class Test
{
    const FLOWS_EMAIL_TYPE_ACTION = 'foo';

    function __construct(array $steps)
    {
        $email_actions = array_reduce(
            $steps,
            fn($result, $step) => $result
                 + (($step['settings']['type'] ?? null) === self::FLOWS_EMAIL_TYPE_ACTION),
            0
        );
        var_export($email_actions);
    }
}

new Test([
    ['settings' => ['type' => 'bar']],
    ['settings' => ['type' => 'foo']],
    [],
    ['settings' => ['type' => 'foo']],
]);
// 2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.