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
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: 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 03 09:01:31 2024 UTC