正如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
此示例中概述的预期行为未定义。Foo
对self::C
的引用是在定义常量之前动态引用的。 如果您要执行Foo::B
我希望它会引发警告。
有关更多上下文,请参阅此"非错误"错误报告:
LSB 的工作原理是存储上次"非转接呼叫"中命名的类 所以这里的关键是要了解什么是转接呼叫:"转接呼叫"是由 self::, parent::, static::.
LSB 及其转发呼叫跟踪是独立于通过 :: 完成的类解析机制。当你使用 self::method(( 或 static::method(( 时,LSB 类是不变的,但是这两个类(可能(会解析并调用不同的 method((。 换句话说,内部状态是相同的,但接下来执行的实际代码不同
无论解释器选择如何处理它,在实际应用程序中以这种方式编码可能是一个坏主意。