Under what conditions does PHP 7 itself refer to the base class?

As noted in the Reddit LOL PHP sub , PHP 7 can use either an extended class or a base class when accessing self , in contrast to PHP 5, which always refers to an extended class.

 <?php class Foo { const A = "FooA"; const B = self::A . self::C; const C = "FooC"; } class Bar extends Foo { const A = "BarA"; const C = "BarC"; } var_dump(Bar::B); 

Try it online

PHP 5

 string(8) "BarABarC" 

PHP 7

 string(8) "FooABarC" 

The behavior of PHP 7 is particularly troubling, since there does not seem to be a simple rule to know when self refers to a base class or an extended class. What are the rules for determining which self class will reference PHP 7?

+7
inheritance php php-7
source share
2 answers

self:: should always refer to the class in which it is used (note that the behavior of PHP 5 is also incorrect.)

This was a bug , fixed in 7.1.4 , which applies to the resolution of self:: and parent:: only inside class constants.

Mostly in:

 const B = self::A . self::C; 

self::C is not yet known, and permission is delayed. At the point of possible resolution, unfortunately, the proper volume was lost.


The problem is also more subtle than just basic and extended, as you can get the value from another expanding class. For example:.

https://3v4l.org/cY1I0

 class A { const selfN = self::N; const N = 'A'; } class B extends A { const N = 'B'; } class C extends A { const N = 'C'; } var_dump(B::selfN); // A var_dump(C::selfN); // A 

In PHP 7.0.0 - 7.1.3 this produces:

 string(1) "B" string(1) "B" 

Although if you change it to:

https://3v4l.org/RltQj

 var_dump(C::selfN); // A var_dump(B::selfN); // A 

You'll get:

 string(1) "C" string(1) "C" 

To avoid this in the affected versions, use the class name, not self:: in the class constant definitions, for example. const selfN = A::N

+2
source share

The expected behavior described in this example is undefined. Foo reference to self::C dynamically refers to a constant until it is defined. If you ran Foo::B , I would expect it to give a warning.

For more information, see this "not a bug" error report :

LSB works by preserving the class called in the last “call forwarding”, so the key here is to understand what the call forwarding is: “call forwarding” is static, which is introduced by self ::, parent ::, static ::.

LSB and its forwarding call tracking are separate mechanisms from class resolution executed via ::. When you use self :: method () or static :: method (), the LSB class does not change, however the two will be (potentially) resolved and will call another method () s. In other words, the internal state is the same, but the current code executed later is different

However, the interpreter decides to process it by encoding something in this way in a real application, probably a bad idea.

+2
source share

All Articles