Home > Mobile >  PHP references doesn't work in Laravel macros
PHP references doesn't work in Laravel macros

Time:11-25

Trying to make a helper method for array that replaces key into given value without return using reference but it doesn't work.

Arr::macro('replaceKey', function (string $from, string $into, array &$inside) {
    if (! array_key_exists($from, $inside)) {
        throw new Exception("Undefined offset: $from");
    }

    $inside[$into] = $inside[$from];

    unset($inside[$from]);
});

Tried the same thing with trait and simple function and it works.

// inside trait

public function replaceKey(string $from, string $into, array &$inside)
{
    if (! array_key_exists($from, $inside)) {
        throw new Exception("Undefined offset: $from");
    }

    $inside[$into] = $inside[$from];

    unset($inside[$from]);
}

Can anyone explain why?

CodePudding user response:

There is a method call before your anonymous function would be getting called when you call a macro; __callStatic gets called. This takes a method name and an array of parameters passed to the method call.

It isn't possible from the method signature side of this method, __callStatic, to declare that an element of the parameters array is to be a reference since it only receives an array of all the arguments passed to the non existing method, replaceKey, as an argument.

You are getting a reference to a copy of the array you are passing to your macro method call in your anonymous function.

CodePudding user response:

You are getting null because you are not returning anything from function.

public function replaceKey(string $from, string $into, array &$inside)
{
    if (! array_key_exists($from, $inside)) {
        throw new Exception("Undefined offset: $from");
    }

    $inside[$into] = $inside[$from];

    unset($inside[$from]);
    return $inside;
}

And macro as well

Arr::macro('replaceKey', function (string $from, string $into, array &$inside) {
    if (! array_key_exists($from, $inside)) {
        throw new Exception("Undefined offset: $from");
    }

    $inside[$into] = $inside[$from];

    unset($inside[$from]);
  
  return $inside;
});

CodePudding user response:

The second parameter of the macro method is a Closure and, in this particular case, an anonymous function.

To pass values by reference you would actually need to use the use keyword and pass the value by reference that way (function (...) use (&$inside)), but because there's no actual variable to pass from the surrounding scope to do that then there's no way of passing that value by reference.

On the other hand, in the trait you are creating a non-anonymous function (aka "function") which allows to pass the value by reference without the use keyword.

  • Related