php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #75474 function scope static variables are not bound to a unique function
Submitted: 2017-11-02 08:58 UTC Modified: 2017-11-03 12:55 UTC
From: nobots dot nospam at example dot org Assigned:
Status: Closed Package: Scripting Engine problem
PHP Version: Irrelevant OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: nobots dot nospam at example dot org
New email:
PHP Version: OS:

 

 [2017-11-02 08:58 UTC] 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


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-11-02 09:29 UTC] requinix@php.net
-Type: Bug +Type: Documentation Problem -Package: *General Issues +Package: Scripting Engine problem
 [2017-11-02 09:29 UTC] 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 09:55 UTC] 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 10:58 UTC] nikic@php.net
-Type: Documentation Problem +Type: Bug
 [2017-11-02 10:58 UTC] 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 18:17 UTC] cmb@php.net
> Static variables should be shared.

I agree.  But what about the current working of function statics
in subclasses, e.g. <https://3v4l.org/4rICv>?
 [2017-11-03 12:55 UTC] nikic@php.net
@cmb: That case is something of a mess, which depends on the order in which you do things. Bob had a patch that normalized this (https://github.com/php/php-src/pull/1899), though it did not go anywhere...
 [2021-02-18 10:40 UTC] nikic@php.net
Automatic comment on behalf of nikita.ppv@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=6b0f14fe3b08be05340c6a4ae03f4131f04d882a
Log: Fixed bug #75474
 [2021-02-18 10:40 UTC] nikic@php.net
-Status: Open +Status: Closed
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 16:01:28 2024 UTC