php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69586 Resolution of static function variables not using forwarded calling information
Submitted: 2015-05-06 15:05 UTC Modified: 2018-02-28 22:25 UTC
From: php at lvl dot fastmail dot com Assigned:
Status: Open Package: Scripting Engine problem
PHP Version: 5.6.8 OS:
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2015-05-06 15:05 UTC] php at lvl dot fastmail dot com
Description:
------------
I ran into some very strange behavior while experimenting with static function variables. Static variables in the function scope appear to be resolved using late static binding: the content of the variable in that function is shared amongst all instances of a class, though each subclass gets its own separate variable space.

This is pretty logical and works fine. As an example, let's create classes Base => Animal => {Cat,Dog}. Base has a function that describes the class, and caches the result in a static function variable $description. Calling describe() on the three different classes correctly gives us three different results: http://3v4l.org/Qldve

However, once you override the describe function in Animal and call parent::describe() from within, it looks like all calling information is lost: the resolution of $description in Base's function scope now always points to Animal's variable space. For example: http://3v4l.org/CcrL8

I would have expected the static function variable and get_called_class() to always refer to the same class/variable space, parent:: or not.

Overriding the function in one of the childmost classes like Dog gives an even stranger result: $description is now correctly a separate value in Cat vs Dog, but calling Animal::describe() now uses the value left by its child class Cat?! See: http://3v4l.org/61P72

Test script:
---------------
class Base {
    public static function describe() {
        echo "--> " . ($calculated = "I am a " . get_called_class() . "\n");
        
        static $cached = null;
        
        if ($cached === null) {
            $cached = $calculated;
        }
        
        return $cached;
    }
}

class Animal extends Base {
    public static function describe() {
        return 'Hello! ' . parent::describe();
    }
}

class Cat extends Animal { }
class Dog extends Animal { }

echo Cat::describe();
echo Dog::describe();
echo Animal::describe();

Expected result:
----------------
--> I am a Cat
Hello! I am a Cat

--> I am a Dog
Hello! I am a Dog

--> I am a Animal
Hello! I am a Animal

Actual result:
--------------
--> I am a Cat
Hello! I am a Cat

--> I am a Dog
Hello! I am a Cat

--> I am a Animal
Hello! I am a Cat

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-02-28 22:25 UTC] cmb@php.net
-Package: Unknown/Other Function +Package: Scripting Engine problem
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Wed May 22 18:01:28 2019 UTC