php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #77537 Unexpected behavior, when using static in constructor
Submitted: 2019-01-29 09:11 UTC Modified: 2021-07-23 07:39 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: dirk dot gerigk at atraveo dot com Assigned: nikic (profile)
Status: Closed Package: Class/Object related
PHP Version: 7.2.14 OS: Windows 10
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: dirk dot gerigk at atraveo dot com
New email:
PHP Version: OS:

 

 [2019-01-29 09:11 UTC] dirk dot gerigk at atraveo dot com
Description:
------------
Unexpected behavior in extended class, when using static variable in constructor and call the method directly

I was testing the concept of immutable classes and was coming to an point where i called the __construct method directly. I injected an static $var in the method and found that unexpected behavior. I seems that the C class that not defines an constructor once call the constructor with the previews incremented static var, but the direct call of the method gets an fresh static var. 
I think it is not normal to call the constructor directly as method, but when it is it should have same result as the class B. 
The call of  $c->__construct(); should get 6 not 1.

Or there any explanation to this?

Test script:
---------------
class A {
 public function __construct(){
     static $test  = 0;
     print (++$test);
 }
}
class B extends A {
    public function __construct(){
        parent::__construct();
    }
}
class C extends A {}

$a = new A;
$a->__construct();
$b = new B;
$b->__construct();
$c = new C;
$c->__construct();

Expected result:
----------------
123456

Actual result:
--------------
123451

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-02-18 11:01 UTC] nikic@php.net
-Status: Open +Status: Duplicate
 [2021-02-18 11:01 UTC] nikic@php.net
In PHP, static variables are bound to a specific method -- if the method is inherited, then it also gets separate static variables. This means that C::__construct() has static variables independent of A::__construct().

I'm going to close this as a duplicate of bug #74198, because the behavior of static variables in methods and their interaction with inheritance is currently not documented.
 [2021-02-18 15:50 UTC] dirk dot gerigk at atraveo dot com
Hi, 

what i dont get is the different behavior of the twice call
$c = new C;
$c->__construct();

the first line calles A::__construct and shows 5
the second lines calls then the method with a separate static and shows 1

So this statement is not valid here:
"if the method is inherited, then it also gets separate static variables"

If this statement is right, then the two calls have to have 1 and 2 as result, no 5 and 1, or?

Normaly u dont call $c->__construct() on an existing object, 
but why is direct call of __construct so different?

But thanks, for the reply.
 [2021-02-18 16:02 UTC] nikic@php.net
-Status: Duplicate +Status: Re-Opened
 [2021-02-18 16:02 UTC] nikic@php.net
Oh, I missed that "new C" and "$c->__construct()" produce different results. Agree that this doesn't seem right.
 [2021-02-18 16:03 UTC] dirk dot gerigk at atraveo dot com
I have tested in another way

class A {
 public function test(){
    static $test  = 0;
    print (++$test);
 }
 public function __construct(){
    $this->test();
 }
}
class B extends A {
    public function __construct(){
        parent::__construct();
    }
}
class C extends A {}

$a = new A;
$a->__construct();
$b = new B;
$b->__construct();
$c = new C;
$c->__construct();

and the result is 121212

So, for now i will keep in mind: 
* dont mess with the constuctor of a class 
* do not use static variables in a constructor

Thanks for the time and work
 [2021-02-18 16:58 UTC] nikic@php.net
-Status: Re-Opened +Status: Verified
 [2021-02-18 16:58 UTC] nikic@php.net
The problem is that we're caching the constructor (and a few magic methods) in the class entry, but end up storing the parent constructor there -- which is always going to be the same unless it uses static variables, thus nobody noticed.

This is a bug, though I'm also increasingly tempted to write a proposal that changes the way we handle static variables in methods, and not use a separate static variable scope on inheritance.
 [2021-07-23 07:39 UTC] nikic@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nikic
 [2021-07-23 07:39 UTC] nikic@php.net
I did end up writing that proposal (https://wiki.php.net/rfc/static_variable_inheritance). This means that as of PHP 8.1 the result will be as written in the "expected result".
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 10 16:01:27 2024 UTC