1

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?

MAChitgarha
  • 3,728
  • 2
  • 33
  • 40
  • I have to say that this is probably the first time I see a function return by reference. Would you mind telling us what could be the advantage of doing so? Why do you need to use references at all? – Dharman Jul 14 '19 at 16:55
  • @Dharman I think it is not really uncommon. There are some already asked questions around this, like [this one](https://stackoverflow.com/questions/7455627) or [this](https://stackoverflow.com/questions/17501165). And yes, in most common cases, it may seem almost useless, but sometimes it helps reducing the code a lot. Describing the use cases is a bit hard, because they are problem-specific. However, it allows us doing things more _dynamically_. It sometimes (not always) gives flexibility to code. – MAChitgarha Jul 14 '19 at 19:01
  • The answer in that post says: *"should be used only rarely and only if you have carefully considered any alternatives first."* Have you considered all alternatives? I am always very sceptical about any use of pass-by-ref, it has very few legitimate use cases. – Dharman Jul 14 '19 at 19:09
  • @Dharman Not sure about all alternatives, but for what I'm working on, yes, probably it's the only solution. BTW, thanks for your attention and looking differently! – MAChitgarha Jul 14 '19 at 19:52

0 Answers0