PHP 7 的自我在什么条件下引用基类?



正如Reddit的LOL PHP子所指出的,PHP 7在引用self时可以使用扩展类或基类,而PHP 5总是引用扩展类。

<?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);

在线试用

菲律宾比索 5

string(8) "BarABarC"

菲律宾比索 7

string(8) "FooABarC"

PHP 7的行为尤其令人担忧,因为似乎没有任何简单的规则可以知道self何时引用基类或扩展类。在 PHP 7 中,确定self将引用哪个类的规则是什么?

self::应该始终引用使用它的类(请注意,PHP 5 的行为也是错误的。

这是一个错误,在 7.1.4 中修复,仅适用于类常量中的self::parent::解析。

基本上在:

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

self::C目前仍未知,解决方案被推迟。不幸的是,在最终解决时,失去了适当的范围。


这个问题也比简单的 base 与扩展更微妙,因为您最终可能会得到来自不同扩展类的值。 例如:

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

在 PHP 7.0.0 到 7.1.3 中,输出:

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

虽然如果你把它换成:

https://3v4l.org/RltQj

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

您将获得:

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

为了避免在受影响的版本中出现这种情况,请使用类名而不是类常量定义中的类名self::,例如const selfN = A::N

此示例中概述的预期行为未定义。Fooself::C的引用是在定义常量之前动态引用的。 如果您要执行Foo::B我希望它会引发警告。

有关更多上下文,请参阅此"非错误"错误报告:

LSB 的工作原理是存储上次"非转接呼叫"中命名的类 所以这里的关键是要了解什么是转接呼叫:"转接呼叫"是由 self::, parent::, static::.

LSB 及其转发呼叫跟踪是独立于通过 :: 完成的类解析机制。当你使用 self::method(( 或 static::method(( 时,LSB 类是不变的,但是这两个类(可能(会解析并调用不同的 method((。 换句话说,内部状态是相同的,但接下来执行的实际代码不同

无论解释器选择如何处理它,在实际应用程序中以这种方式编码可能是一个坏主意。

最新更新