为什么 PHP 的空合并运算符 (??) 不能对具有不同可见性的 class 常量起作用?
Why doesn't PHP's null coalescing operator (??) work on class constants with different visibilities?
考虑下面的例子。 Class a 有 private const SOMETHING
,但 class b 有 protected const SOMETHING
.
class a {
private const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING ?? self::SOMETHING;
}
}
class b extends a {
protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
输出:
This is b!
但是现在如果我在class b中注释掉SOMETHING
的定义,就会抛出一个错误:
class a {
private const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING ?? self::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
输出:
Fatal error: Uncaught Error: Cannot access private const b::SOMETHING in {file}.php:7
但是,在 class 中将可见性从 private const SOMETHING
更改为 protected const SOMETHING
可以解决此问题。
class a {
protected const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING ?? self::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
现在输出符合预期:
This is a!
我不明白为什么 php 在应用空合并运算符之前评估 b::SOMETHING,根据 the documentation:
The null coalescing operator (??) has been added as syntactic sugar
for the common case of needing to use a ternary in conjunction with
isset(). It returns its first operand if it exists and is not NULL;
otherwise it returns its second operand.
由于未设置 b::SOMETHING,为什么第一个示例不起作用,并且需要对基数 class 中的常量保持一致的可见性?
Since b::SOMETHING is not set, why doesn't the first example work and a consistent visibility is required for the constant in the base class?
B::SOMETHING
已设置。设置它是因为 B
扩展了 A
并且您已将 SOMETHING
定义为 A
的常量。问题不是它没有设置,问题是你没有授予 B
访问它的权限,所以它真的不适合 null 合并格式。
这实际上归结为 private
可见性使用不当。
正如你之前承认的那样:
The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
这意味着此运算符在您的第二个代码块中工作正常,因为在 class b const 中存在一些东西!但它无法访问。您无法使用 ?? 检查现有封装字段的存在或 'NULL value state'或者使用 isset()。
我猜封装字段的检查逻辑以 :
的方式工作
存在? ->是-> 是否为空? -> 错误(可以'访问它以检查值)
其他代码块块正常工作
感谢@Devon 和@Dormilich 的回复。
TL;DR:您不能对常量使用 null 合并运算符 (??
)。您必须改用 defined()
。
根据the documentation for the null coalescing operator (??):
The null coalescing operator (??) has been added as syntactic sugar
for the common case of needing to use a ternary in conjunction with
isset(). It returns its first operand if it exists and is not NULL;
otherwise it returns its second operand.
意味着 $x ?? $y
对于 isset($x) ? $x : $y
是 shorthand。这就是问题所在,因为 documentation for isset 明确指出:
Warning: isset() only works with variables as passing anything else
will result in a parse error. For checking if constants are set use
the defined() function.
这就是引发我在问题中描述的致命 php 错误的原因。相反,解决方案是取消空合并运算符并将其替换为 defined()
:
class a {
private const SOMETHING = 'This is a!';
public static function outputSomething() {
return defined('static::SOMETHING') ? static::SOMETHING : self::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
第二种解决方案是首先更改代码的工作方式。正如@Devon 正确指出的那样, a::SOMETHING
的 private
可见性阻止 class b 看到它,因此未定义 b::SOMETHING
。但是,当 a::SOMETHING
的可见性更改为 protected
时, class b 可以看到它并且 b::SOMETHING
可以引用它。此代码根本不需要空合并运算符,可以只使用 static::SOMETHING
而无需任何条件:
class a {
protected const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
考虑下面的例子。 Class a 有 private const SOMETHING
,但 class b 有 protected const SOMETHING
.
class a {
private const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING ?? self::SOMETHING;
}
}
class b extends a {
protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
输出:
This is b!
但是现在如果我在class b中注释掉SOMETHING
的定义,就会抛出一个错误:
class a {
private const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING ?? self::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
输出:
Fatal error: Uncaught Error: Cannot access private const b::SOMETHING in {file}.php:7
但是,在 class 中将可见性从 private const SOMETHING
更改为 protected const SOMETHING
可以解决此问题。
class a {
protected const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING ?? self::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
现在输出符合预期:
This is a!
我不明白为什么 php 在应用空合并运算符之前评估 b::SOMETHING,根据 the documentation:
The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
由于未设置 b::SOMETHING,为什么第一个示例不起作用,并且需要对基数 class 中的常量保持一致的可见性?
Since b::SOMETHING is not set, why doesn't the first example work and a consistent visibility is required for the constant in the base class?
B::SOMETHING
已设置。设置它是因为 B
扩展了 A
并且您已将 SOMETHING
定义为 A
的常量。问题不是它没有设置,问题是你没有授予 B
访问它的权限,所以它真的不适合 null 合并格式。
这实际上归结为 private
可见性使用不当。
正如你之前承认的那样:
The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
这意味着此运算符在您的第二个代码块中工作正常,因为在 class b const 中存在一些东西!但它无法访问。您无法使用 ?? 检查现有封装字段的存在或 'NULL value state'或者使用 isset()。
我猜封装字段的检查逻辑以 :
的方式工作 存在? ->是-> 是否为空? -> 错误(可以'访问它以检查值)
其他代码块块正常工作
感谢@Devon 和@Dormilich 的回复。
TL;DR:您不能对常量使用 null 合并运算符 (??
)。您必须改用 defined()
。
根据the documentation for the null coalescing operator (??):
The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.
意味着 $x ?? $y
对于 isset($x) ? $x : $y
是 shorthand。这就是问题所在,因为 documentation for isset 明确指出:
Warning: isset() only works with variables as passing anything else will result in a parse error. For checking if constants are set use the defined() function.
这就是引发我在问题中描述的致命 php 错误的原因。相反,解决方案是取消空合并运算符并将其替换为 defined()
:
class a {
private const SOMETHING = 'This is a!';
public static function outputSomething() {
return defined('static::SOMETHING') ? static::SOMETHING : self::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();
第二种解决方案是首先更改代码的工作方式。正如@Devon 正确指出的那样, a::SOMETHING
的 private
可见性阻止 class b 看到它,因此未定义 b::SOMETHING
。但是,当 a::SOMETHING
的可见性更改为 protected
时, class b 可以看到它并且 b::SOMETHING
可以引用它。此代码根本不需要空合并运算符,可以只使用 static::SOMETHING
而无需任何条件:
class a {
protected const SOMETHING = 'This is a!';
public static function outputSomething() {
return static::SOMETHING;
}
}
class b extends a {
//protected const SOMETHING = 'This is b!';
}
echo (new b())::outputSomething();