Hi,
I have reported a bug in Mai 2019 but did not get any response here
https://bugs.php.net/bug.php?id=77985.
The problem is that "static::class" as well as "get_called_class()" used
within a method resolves to a different class if this method was called
with "self::method". Interestingly it works as expected if the method
got called with "ClassName::method".
I send it here because fixing this could result in a hard to find BC
break and it could be a good idea to handle this in 8.0.
class A {
static function call() {
self::method();
$self = self::class;
$self::method();
}
static function method() { echo static::class; }
}
class B extends A {}
B::call(); // displays "BA" instead of "AA"
In case this is "Not a Bug" please explain to me why the result of
"self::method()" is different then "$self = self::class; $self::method();".
Thanks,
Marc
class A {
static function call() {
self::method();$self = self::class;
$self::method();
}
static function method() { echo static::class; }
}class B extends A {}
B::call(); // displays "BA" instead of "AA"
Someone else may be able to confirm if this is a bug or working as designed, but what seems to be happening is that the value of "static" is not reset when calling a method using self::
This doesn't just apply to getting the class name, but to actual static calls; for instance:
https://3v4l.org/p2g8E
class A {
static function call() {
self::method1();
}
static function method1() {
static::method2();
}
static function method2() {
echo 'Base definition';
}
}
class B extends A {
static function method2() {
echo 'Override';
}
}
B::call();
If the call to self::method1() reset the called class, this would run A::method2() and echo 'Base definition'; instead, the called class is remembered, and it calls B::method2() and echoes 'Override'.
If you explicitly call A::method1(), as you are effectively doing in your self::class example, the "called class" information is reset, and the call goes through to A::method2().
Regards,
Hi Marc,
--
Rowan Tommins
[IMSoP]
This is expected behaviour given my understanding of how late static binding works:
If there is a chain of “self::” calls that ultimately ends in “static::someMethod”, then PHP behaves as if every preceding call was a call to “static::”, not “self::”. In your second call you’re explicitly overriding that resolution by changing using (self::class)::someMethod, which PHP always treats as A::someMethod, thus producing the expected output.
Hi,
I have reported a bug in Mai 2019 but did not get any response here https://bugs.php.net/bug.php?id=77985.
The problem is that "static::class" as well as "get_called_class()" used within a method resolves to a different class if this method was called with "self::method". Interestingly it works as expected if the method got called with "ClassName::method".
I send it here because fixing this could result in a hard to find BC break and it could be a good idea to handle this in 8.0.
class A {
static function call() {
self::method();$self = self::class; $self::method(); } static function method() { echo static::class; }
}
class B extends A {}
B::call(); // displays "BA" instead of "AA"
In case this is "Not a Bug" please explain to me why the result of "self::method()" is different then "$self = self::class; $self::method();".
Thanks,
Marc
Hi,
This is expected behaviour given my understanding of how late static binding works:
If there is a chain of “self::” calls that ultimately ends in “static::someMethod”, then PHP behaves as if every preceding call was a call to “static::”, not “self::”. In your second call you’re explicitly overriding that resolution by changing using (self::class)::someMethod, which PHP always treats as A::someMethod, thus producing the expected output.
Thanks for explaining.
I couldn't find any information for this behavior in the documentation -
Is that documented anywhere?
Does it make sense? -> I have read "self::" all time as a shortcut for
"MyClass::" until I noticed this is not the case and I expect most PHP
devs would explain it this way.
Is there a reason why self:: doesn't reset the internal "static" reference?
Sorry for all these questions.
Sometimes the world could be so simple until it turns out it isn't for
no reason.
Thanks,
Marc
Hi,
This is expected behaviour given my understanding of how late static
binding works:If there is a chain of “self::” calls that ultimately ends in
“static::someMethod”, then PHP behaves as if every preceding call was a
call to “static::”, not “self::”. In your second call you’re explicitly
overriding that resolution by changing using (self::class)::someMethod,
which PHP always treats as A::someMethod, thus producing the expected
output.Thanks for explaining.
I couldn't find any information for this behavior in the documentation -
Is that documented anywhere?Does it make sense? -> I have read "self::" all time as a shortcut for
"MyClass::" until I noticed this is not the case and I expect most PHP
devs would explain it this way.Is there a reason why self:: doesn't reset the internal "static" reference?
Sorry for all these questions.
Sometimes the world could be so simple until it turns out it isn't for
no reason.Thanks,
Marc
See https://wiki.php.net/rfc/lsb_parentself_forwarding, which is the RFC
that added this behavior.
Nikita
Does it make sense? -> I have read "self::" all time as a shortcut for
"MyClass::" until I noticed this is not the case and I expect most PHP
devs would explain it this way.Is there a reason why self:: doesn't reset the internal "static" reference?
A reasonably intuitive parallel that occurred to me is that $this is also
maintained through self:: calls (as long as they're not to a method
declared static).
So if you replace the static:: call in my previous example with a $this->
call, you get the same result:
https://3v4l.org/deRcD
class A {
function call() {
self::method1();
}
function method1() {
$this->method2();
}
function method2() {
echo 'Base definition';
}
}
class B extends A {
function method2() {
echo 'Override';
}
}
(new B)->call(); # echoes 'Override'
Regards,
Rowan Tommins
[IMSoP]
Thank you all for explaining.
This helps a lot!
Marc
Does it make sense? -> I have read "self::" all time as a shortcut for
"MyClass::" until I noticed this is not the case and I expect most PHP
devs would explain it this way.Is there a reason why self:: doesn't reset the internal "static" reference?
A reasonably intuitive parallel that occurred to me is that $this is also
maintained through self:: calls (as long as they're not to a method
declared static).So if you replace the static:: call in my previous example with a $this->
call, you get the same result:https://3v4l.org/deRcD
class A {
function call() {
self::method1();
}
function method1() {
$this->method2();
}
function method2() {
echo 'Base definition';
}
}
class B extends A {
function method2() {
echo 'Override';
}
}
(new B)->call(); # echoes 'Override'Regards,