# Closures and __FUNCTION__

- Thread: https://externals.io/message/43665
- Original archive: https://news-web.php.net/php.internals/43665
- Started by Peter Danenberg on 2009-04-12T02:51:00+00:00
- Messages: 11
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #43665 — Peter Danenberg — 2009-04-12T02:51:00+00:00

URL: https://externals.io/message/43665#43665

The original anonymous functions patch[1] contained support for
__FUNCTION__ as a recursion mechanism in closures, such that I should
be able to do something like this:

  $factorial = function($n) {
      if ($n == 1)
        return 1;
      else
        return $n * call_user_func(__FUNCTION__, $n - 1);                                                                                                          
    };

  print $factorial(3);                  // => 6                                                                                                          

It fails with a warning, though:

  Warning: `call_user_func()` expects parameter 1 to be a valid
  callback, function '{closure}' not found or invalid function name

Is there another recursion mechanism for closures besides something
like the $GLOBALS['factorial'] hack?

Footnotes: 
[1]  http://marc.info/?l=php-internals&m=119995982228453&w=2

---

## #43667 — Justin Martin — 2009-04-13T07:14:04+00:00

URL: https://externals.io/message/43665#43667 · In reply to: #43665

Hi Peter,

If I recall correctly, you can use the 'use' keyword.

$factorial = function($foo) use ($factorial) {
	$factorial($foo);
}

$factorial('Hello World!');

I'm still having issues compiling 5.3 on my system, so I haven't tested
this.

Thanks,
Justin Martin

Peter Danenberg wrote:
> The original anonymous functions patch[1] contained support for
> __FUNCTION__ as a recursion mechanism in closures, such that I should
> be able to do something like this:
> 
>   $factorial = function($n) {
>       if ($n == 1)
>         return 1;
>       else
>         return $n * call_user_func(__FUNCTION__, $n - 1);                                                                                                          
>     };
> 
>   print $factorial(3);                  // => 6                                                                                                          
> 
> It fails with a warning, though:
> 
>   Warning: `call_user_func()` expects parameter 1 to be a valid
>   callback, function '{closure}' not found or invalid function name
> 
> Is there another recursion mechanism for closures besides something
> like the $GLOBALS['factorial'] hack?
> 
> Footnotes: 
> [1]  http://marc.info/?l=php-internals&m=119995982228453&w=2

---

## #43668 — Justin Martin — 2009-04-13T08:00:09+00:00

URL: https://externals.io/message/43665#43668 · In reply to: #43667

In addendum I'd like to correct the syntax that I had someone in IRC test.

Apparently it works as such:

$foo = NULL;
$foo = function($foo) use (&$foo) {
	...
}

Still rather hackish, but better than globals I suppose?

Thanks,
Justin Martin

Justin Martin wrote:
> Hi Peter,
> 
> If I recall correctly, you can use the 'use' keyword.
> 
> $factorial = function($foo) use ($factorial) {
> 	$factorial($foo);
> }
> 
> $factorial('Hello World!');
> 
> I'm still having issues compiling 5.3 on my system, so I haven't tested
> this.
> 
> Thanks,
> Justin Martin
> 
> Peter Danenberg wrote:
> > […]

---

## #43669 — Peter Danenberg — 2009-04-13T08:03:52+00:00

URL: https://externals.io/message/43665#43669 · In reply to: #43667

Quoth Justin Martin on Pungenday, the 30th of Discord:
> If I recall correctly, you can use the 'use' keyword.

Thanks, Justin; that occurred to me, too. But the following results in
"Notice: Undefined variable: factorial":

  $factorial = function($n) use ($factorial) {
      if ($n == 1)
        return 1;
      else
        return $n * $factorial($n - 1);
    };

  print $factorial(3);

and eventually "PHP Fatal error:  Function name must be a string."

---

## #43670 — Peter Danenberg — 2009-04-13T08:05:06+00:00

URL: https://externals.io/message/43665#43670 · In reply to: #43668

Quoth Justin Martin on Pungenday, the 30th of Discord:
> Apparently it works as such:
> 
> $foo = NULL;
> $foo = function($foo) use (&$foo) {
> 	...
> }
> 
> Still rather hackish, but better than globals I suppose?

Heh; amazing. I'm not going to pretend to comprehend this hack; but
I'll use it, nonetheless.

---

## #43671 — Justin Martin — 2009-04-13T08:09:00+00:00

URL: https://externals.io/message/43665#43671 · In reply to: #43670

Well, it's a rather simple bit of logic.

First, we define $foo and load it with `NULL` so that it is available for
referencing. Next, in terms of program logic, we create a closure with a
lexical ('use') variable of a reference to $foo, which is then assigned
to $foo. Thus, the reference to $foo in the closure declaration now
points to the closure itself.

Recursion is always complicated :P

Thanks,
Justin Martin

Peter Danenberg wrote:
> Quoth Justin Martin on Pungenday, the 30th of Discord:
> > […]
> 
> Heh; amazing. I'm not going to pretend to comprehend this hack; but
> I'll use it, nonetheless.

---

## #43672 — Peter Danenberg — 2009-04-13T08:17:53+00:00

URL: https://externals.io/message/43665#43672 · In reply to: #43671

> First, we define $foo and load it with `NULL` so that it is available for
> referencing.

It turns out loading $foo is superfluous; I can get away with just:

  $foo = function($foo) use (&$foo) {
       $foo();
  }

> Next, in terms of program logic, we create a closure with a lexical
> ('use') variable of a reference to $foo, which is then assigned to
> $foo. Thus, the reference to $foo in the closure declaration now
> points to the closure itself.

That much is clear; but why $foo is all of the sudden bound within the
closure when I use by reference (&$foo) as opposed to use by value
($foo) is mysterious.

---

## #43673 — Justin Martin — 2009-04-13T08:20:00+00:00

URL: https://externals.io/message/43665#43673 · In reply to: #43672

I suppose it's an issue of cloning. Perhaps there's some difference
between a cloned closure and a referenced closure?

Thanks,
Justin Martin

Peter Danenberg wrote:
> > […]
> 
> It turns out loading $foo is superfluous; I can get away with just:
> 
>   $foo = function($foo) use (&$foo) {
>        $foo();
>   }
> 
> > […]
> 
> That much is clear; but why $foo is all of the sudden bound within the
> closure when I use by reference (&$foo) as opposed to use by value
> ($foo) is mysterious.

---

## #43678 — Marcin Kurzyna — 2009-04-13T18:10:29+00:00

URL: https://externals.io/message/43665#43678 · In reply to: #43669

Peter Danenberg pisze:
> Quoth Justin Martin on Pungenday, the 30th of Discord:
> > […]
> 
> Thanks, Justin; that occurred to me, too. But the following results in
> "Notice: Undefined variable: factorial":
> 
>   $factorial = function($n) use ($factorial) {
>       if ($n == 1)
>         return 1;
>       else
>         return $n * $factorial($n - 1);
>     };
> 
>   print $factorial(3);
> 
> and eventually "PHP Fatal error:  Function name must be a string."

This is correct.

See: in the first example you were referencing previously defined $foo 
(which at the moment of first reference was NULL). It was only later 
replaces with closure itself but it worked because of the reference.

On the other hand when you copy variable you try to use undefined 
$factorial (thus the notice). It is because at the moment of "using" the 
variable it's undefined. Only later it becomes our closure, however then 
  it's after evaluation of use.

Although this is probably more a generals topic. The lack of 
__FUNCTION__ inside the closure is however something i'd like to hear 
more about.

Any word on this from the devs?

TIA,
Marcin

---

## #43684 — Stanislav Malyshev — 2009-04-13T21:03:12+00:00

URL: https://externals.io/message/43665#43684 · In reply to: #43665

Hi!

> The original anonymous functions patch[1] contained support for
> __FUNCTION__ as a recursion mechanism in closures, such that I should
> be able to do something like this:
> 
>   $factorial = function($n) {
>       if ($n == 1)
>         return 1;
>       else
>         return $n * call_user_func(__FUNCTION__, $n - 1);                                                                                                          
>     };
> 
>   print $factorial(3);                  // => 6                                                                                                          

You can also do it the hard way (that's how some languages not having 
luxury of being PHP do it ;), using something called Y-Combinator 
(http://en.wikipedia.org/wiki/Y_combinator), which allows you to unroll 
recursive function into non-recursive one. This looks like this:

function Y($F) {
	$func =  function ($f) { return $f($f); };
	return $func(function ($f) use($F) {
	        return $F(function ($x) use($f) {
			$ff = $f($f);
			return $ff($x);
         	});
     	});
}

This is the generic combinator function. Now your factorial function 
would look like:

$factorial = Y(function($fact) {
	return function($n) use($fact) {
		return ($n == 0)?1:$n*$fact($n-1);
	};
});

And then you can do just this:

var_dump($factorial(3));

Look, ma, no recursion! :)
If it looks confusing, then you're right - it is :) It may be not what 
you would want to do in your code (or maybe you do), but this is yet 
another thing now possible with PHP.

On the other hand, we may want to add some way to refer to the closure 
currently being run. We should have this information, so it should not 
be too hard to do.
-- 
Stanislav Malyshev, Zend Software Architect
stas@zend.com   http://www.zend.com/
(408)253-8829   MSN: stas@zend.com

---

## #43686 — Peter Danenberg — 2009-04-13T21:34:43+00:00

URL: https://externals.io/message/43665#43686 · In reply to: #43684

> function Y($F) {
> 	$func =  function ($f) { return $f($f); };
> 	return $func(function ($f) use($F) {
> 	        return $F(function ($x) use($f) {
> 			$ff = $f($f);
> 			return $ff($x);
>         	});
>     	});
> }

That's interesting; I should be able to implement tail-recursion in a
similar fashion using, say, trampolines,[1] shouldn't I?

> On the other hand, we may want to add some way to refer to the
> closure currently being run. We should have this information, so it
> should not be too hard to do.

That would be great; we could even do some benchmarking against the
Y-combinator (which I've always loved, but never used).

Footnotes: 
[1]  http://en.wikipedia.org/wiki/Tail_recursion#Implementation_methods
