php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #77985 Wrong resolution of "Late Static Binding" after self::method()
Submitted: 2019-05-07 19:31 UTC Modified: 2020-03-09 10:26 UTC
From: dev at mabe dot berlin Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: Irrelevant OS: Linux
Private report: No CVE-ID: None
 [2019-05-07 19:31 UTC] dev at mabe dot berlin
Description:
------------
Wrong resolution of the referenced class that was initially called (Late Static Binding) if it gets called using static::method().

Both, static::class as well as get_called_class() result into the wrong class name.

Simplified explanation from test script:

1. calling "B:call()"

2. -> calling "self::getStaticClass()" defined in "A::call"
  This should get resolved to "A::getStaticClass()"

3. -> returning "static::class"
  This should get resolved to "A:class" as it was called by "A::getStaticClass()"


Test script:
---------------
<?php

class A {
    static function getStaticClass(){ return static::class; }
    static function getCalledClass() { return get_called_class(); }
    static function call(){
        $self = self::class;
        echo $self;
        echo $self::getStaticClass();
        echo $self::getCalledClass();
        echo self::getStaticClass();
        echo self::getCalledClass();

        echo PHP_EOL;

        $static = static::class;
        echo $static;
        echo $static::getStaticClass();
        echo $static::getCalledClass();
        echo static::getStaticClass();
        echo static::getCalledClass();

        echo PHP_EOL;
        
        $calledClass = get_called_class();
        echo $calledClass;
        echo $calledClass::getStaticClass();
        echo $calledClass::getCalledClass();

        echo PHP_EOL;
    }
}

class B extends A {}

echo 'A:call()', PHP_EOL;
A::call();

echo 'B:call()', PHP_EOL;
B::call();

Expected result:
----------------
A:call()
AAAAA
AAAAA
AAA
B:call()
AAAAA
BBBBB
BBB

Actual result:
--------------
A:call()
AAAAA
AAAAA
AAA
B:call()
AAABB      <- The last two cases should resolve to A instead of B
BBBBB
BBB

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-05-07 19:33 UTC] dev at mabe dot berlin
-Summary: Wrong resolution of "Late Static Binding" after static::method() +Summary: Wrong resolution of "Late Static Binding" after self::method()
 [2019-05-07 19:33 UTC] dev at mabe dot berlin
Sorry in my first sentence I mean "if it got called using self::method()"
 [2020-03-09 10:23 UTC] php at yopmail dot com
See https://externals.io/message/108895#108904 for why that's intended behavior.

Shorter example:

```
<?php

class A {
    public static function test() {
        A::f();
        self::f();
        static::f();
    }
    protected static function f() {
        echo 'A, ', static::class, PHP_EOL;
    }
}

class B extends A {
    protected static function f() {
        echo 'B, ', static::class, PHP_EOL;
    }
}

B::test();
```

Output:
-------
A, A
A, B
B, B
 [2020-03-09 10:26 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2020-03-09 10:26 UTC] nikic@php.net
As explained in the linked thread, this behavior is intentional, so I'm closing this bug.

I think the main use-case here is inheriting LSB scope when calling parent::method() -- the self::method() case is more a consistency consideration.
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Sun Jul 12 03:01:25 2020 UTC