Bug #75474 [Opn]: function scope static variables are not bound to a unique function

From: Date: Thu, 02 Nov 2017 18:17:28 +0000
Subject: Bug #75474 [Opn]: function scope static variables are not bound to a unique function
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-212412@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=75474&edit=1

 ID:                 75474
 Updated by:         cmb@php.net
 Reported by:        nobots dot nospam at example dot org
 Summary:            function scope static variables are not bound to a
                     unique function
 Status:             Open
 Type:               Bug
 Package:            Scripting Engine problem
 PHP Version:        Irrelevant
 Block user comment: N
 Private report:     N

 New Comment:

> Static variables should be shared.

I agree.  But what about the current working of function statics
in subclasses, e.g. <https://3v4l.org/4rICv>?


Previous Comments:
------------------------------------------------------------------------
[2017-11-02 10:58:17] nikic@php.net

Static variables should be shared. It should not make a difference whether a callable is invoked
directly or indirected through Closure::fromCallable(). The current behavior will also negatively
interact with future plans for more first-class callable references based on closure objects.

As for returning the same object, I don't think we're going to add such a guarantee. In
any case, it should be part of a separate request, as it is unrelated to the static variable bug
(which are due to internal state management, not which object is being used.)

------------------------------------------------------------------------
[2017-11-02 09:55:18] Wes dot example at example dot org

yes you can document the incomplete functionality if you want, but it won't make the user
experience any better

comparing objects seems to me a very basic feature

I don't really care about statics as I rarely use them, but again I doubt the current behavior
is what people expect

what's the point of Closure::fromCallable("foo") then? if I did function(...$a){
return foo(...$a); } I'd at least have the static variables working

------------------------------------------------------------------------
[2017-11-02 09:29:25] requinix@php.net

> essentially Closure::fromCallable() and $RF->getClosure() should always return the same
> Closure object
I disagree. Both of them are documented to return "new" (Closure::fromCallable) or
"dynamically created" (ReflectionFunction::getClosure) closures - copies of the original,
not shallow references to it. And that implies copies of any static variables it may have, which is
why the first fromCallable shows [0,1] instead of [1].

Regular functions and closures are two separate things: a function is not a closure, and a closure
is not a function*. Creating a closure from a function is not like creating an alias or performing
some sort of import (cf. traits in classes).

How about we clarify the behavior in the documentation?

* It's an object (\Closure) that behaves like a function, and is defined using syntax that
resembles that of a function, but is not actually a function.

------------------------------------------------------------------------
[2017-11-02 08:58:58] nobots dot nospam at example dot org

Description:
------------
Every time a closure is generated from a named function, it creates a copy of the static variables
rather than modifying the original named function's ones.

function bar($k, $v){
    static $foo = [];
    $foo[$k] = $v;
    return $foo;
}

var_dump(bar(0, 0));
var_dump(Closure::fromCallable("bar")(1, 1));
var_dump(bar(2, 2));
var_dump(Closure::fromCallable("bar")(3, 3));
$RF = new ReflectionFunction("bar");
var_dump($RF->getClosure()(4, 4));
var_dump(bar(5, 5));

the result after the last bar() call should be [0,1,2,3,4,5]
but it is [0 => 0, 2 => 2, 5 => 5]

essentially Closure::fromCallable() and $RF->getClosure() should always
return the same Closure object:

assert(Closure::fromCallable("foo") === Closure::fromCallable("foo"));
assert($RF->getClosure() === $RF->getClosure());
assert(Closure::fromCallable("foo") === $RF->getClosure());

Unless they are rebound to a different $this or cloned.

Thanks



------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=75474&edit=1


Thread (5 messages)

« previous php.bugs (#212412) next »