Bug #72916 [Opn->Nab]: get_called_class is wrong after calling via self:: from non-static method

From: Date: Wed, 12 Apr 2017 21:36:33 +0000
Subject: Bug #72916 [Opn->Nab]: get_called_class is wrong after calling via self:: from non-static method
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-208502@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=72916&edit=1

 ID:                 72916
 Updated by:         requinix@php.net
 Reported by:        gharlan at web dot de
 Summary:            get_called_class is wrong after calling via self::
                     from non-static method
-Status:             Open
+Status:             Not a bug
 Type:               Bug
 Package:            Class/Object related
 PHP Version:        7.0.10
 Block user comment: N
 Private report:     N

 New Comment:

I was having a hard time deciding whether this is a bug until I went to the LSB docs to see what
they said.
http://php.net/manual/en/language.oop5.late-static-bindings.php

LSB works by
> storing the class named in the last "non-forwarding call"
so the key here is to understand what a forwarding call is:
> A "forwarding call" is a static one that is introduced by self::, parent::, static::,

That means the calls in the stack are
  (new Child)->bar(); // not a forwarded call - LSB->Child
  self::getClass();   // forwarded call - LSB unchanged

Thus get_called_class() should return Child.

"What about Foo::getClass?"
Foo:: is not a forwarding call so LSB begins tracking Foo.

"Okay, but what about static::getClass?"
Before LSB there was no way to get "inheritance" with static calls: self:: would not go
down the inheritance hierarchy, remaining only in the current class or going to an ancestor. LSB and
its static:: was the solution.

What made static:: different from self:: was that
> static:: will not be resolved using the class where the method is defined but
> it will rather be computed using runtime information

That "runtime information" would be the LSB class, thus static::getClass() will call
Child::getClass().

There's an important distinction to be made here: LSB and its forwarded call tracking are
separate mechanisms from class resolution done through ::. When you use self::method() or
static::method() the LSB class is unchanged, however the two will (potentially) resolve to and call
different method()s.
In other words, the internal state is the same but the actual code being executed next differs, and
what get_called_class() does is give you a peek into that internal state.

So in that sense the "static" in late-static bindings could be misleading. It's not
about when the first static call was made but about tracking the first class invoked directly (ie,
via an instance or its name) and then *using that* with future static:: calls.


Previous Comments:
------------------------------------------------------------------------
[2017-04-12 19:37:44] mail at pmmaga dot net

Is it possible you are expecting the behavior of get_class instead of get_called_class?

From the documentation, get_called_class: "Gets the name of the class the static method is
called in."

In your example, the result "Child" follows that rule.

------------------------------------------------------------------------
[2016-08-21 23:18:21] gharlan at web dot de

Description:
------------
The return value of get_called_class() is wrong, when it is called from a static method that is
called via self::method() in a non-static method.

Test script:
---------------
<?php
class Foo {
    protected static function getClass() {
        return get_called_class();
    }
    
    public function bar() {
        echo 'Foo: ', Foo::getClass(), "\n";
        echo 'self: ', self::getClass(), "\n";
        echo 'static: ', static::getClass(), "\n";
    }
}

class Child extends Foo {
    protected static function getClass() {
        return 'x';
    }
}

(new Child)->bar();

Expected result:
----------------
Foo: Foo
self: Foo
static: x

Actual result:
--------------
Foo: Foo
self: Child
static: x


------------------------------------------------------------------------



--
Edit this bug report at https://bugs.php.net/bug.php?id=72916&edit=1


Thread (3 messages)

« previous php.bugs (#208502) next »