MAChitgarha
MAChitgarha

Reputation: 4288

How to assign a closure's return value to a variable by-reference, even if the closure returns by-value?

I have a method which gets a callable as an argument. The callable is called with some arguments which can be gotten by-value or by-reference, and it may return a value, either by-value or by-reference, or not. In the case of returning a value, it must be returned from the closure by the method as exactly as is. If the value is by-reference, the method must return it by-reference, and vice versa.

The problem is that there is no way to determine whether the value is returned by-reference or not. Yes, it can be detected whether the closure returns any values or not; but when I try to get the reference of a closure's return value which is returned by-value, I will get the following notice:

PHP Notice:  Only variables should be assigned by reference in ... on line xxx

Again, the method returns the closure's return value as is (i.e. dynamically). This is what I try to achieve:

class Example
{
    protected $data = 15;

    // Pay attention to this, returning by-reference
    protected function &doOnData(callable $function)
    {
        return $function($this->data);
    }

    public function increment(): void
    {
        // No notices, because the closure is defined to return by-reference
        $data = &$this->doOnData(function &(&$data) {
            return $data;
        });
        $data++;
    }

    public function get()
    {
        // Notice, why you defined the closure to return by-value?
        // Defining the closure to return by-reference fixes the problem
        // temporarily (i.e. defining as: function &($data))
        return $this->doOnData(function ($data) {
            return $data;
        });
    }

    public function printData()
    {
        echo $this->data;
    }
}

$example = new Example();

$example->increment();
$example->printData(); // Prints: 16

$data = $example->get(); // Notice!
echo $data; // Prints: 16

As you see in the example, the notice will only be produced when you pass a returning-by-value closure to Example::doOnData(), and you cannot get its return value reference. In this case, the above notice will be generated (should it be generated? I don't know!).

A solution might be using the @ (at sign) operator, which is stupidly bad (see: 1 and 2). Saving the reference of the closure to a variable, and then returning the variable doesn't change anything (AFAIK). Also, adding an ampersand (&) before the closure inside Example::get(), as described in code comments, is not a solution for that, and have some side effects (e.g. every closure must be defined to return by-reference to prevent the notice, too bad, the user doesn't know that). So, please don't suggest these things!

Is there any way to prevent the notice? Am I doing something wrong? Generally speaking, can I determine whether the value is returned by-value or by-reference (i.e. something like is_reference())? Is there any other solutions to get it done?

Upvotes: 1

Views: 153

Answers (0)

Related Questions