Почему оператор PHP с нулевым объединением (??) не работает с константами классов с различной видимостью?

Рассмотрим пример ниже. Класс А имеет private const SOMETHING, но класс б имеет 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!

Но теперь, если я закомментирую определение для SOMETHING в классе b выдается ошибка:

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

Тем не менее, изменение видимости от 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 до применения оператора объединения нулей, который в соответствии с документация:

Нулевой оператор объединения (??) был добавлен как синтаксический сахар
для общего случая необходимости использовать троичный в сочетании с
Исеть (). Возвращает свой первый операнд, если он существует и не равен NULL;
в противном случае он возвращает свой второй операнд.

Поскольку b :: SOMETHING не задано, почему не работает первый пример, и для константы в базовом классе требуется согласованная видимость?

4

Решение

Поскольку b :: SOMETHING не задано, почему не работает первый пример, и для константы в базовом классе требуется согласованная видимость?

B::SOMETHING установлено. Это установлено, потому что B продолжается A и вы определили SOMETHING как константа A, Проблема не в том, что он не установлен, проблема в том, что вы не предоставили B доступ к нему, так что он действительно не вписывается в нулевой формат объединения.

Это действительно сводится к неправильному использованию private видимость.

1

Другие решения

Спасибо @Devon и @Dormilich за их ответы.

TL; DR: Вы не можете использовать оператор объединения нулей (??с константами. Вы должны использовать defined() вместо.

В соответствии с документация для оператора объединения нулей (??):

Нулевой оператор объединения (??) был добавлен как синтаксический сахар
для общего случая необходимости использовать троичный в сочетании с
Исеть (). Возвращает свой первый операнд, если он существует и не равен NULL;
в противном случае он возвращает свой второй операнд.

Означающий, что $x ?? $y это сокращение для isset($x) ? $x : $y, И здесь кроется проблема, потому что документация для isset прямо заявляет:

Предупреждение: isset () работает только с переменными, передавая что-либо еще
приведет к ошибке разбора. Для проверки, установлены ли константы, используйте
определенная () функция.

Вот что выдает роковую ошибку 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, private видимость a::SOMETHING препятствует тому, чтобы класс b видел это, так b::SOMETHING не определено. Тем не менее, когда видимость a::SOMETHING изменено на protected, класс В может видеть это и b::SOMETHING ссылается на это. Этот код вообще не нуждается в операторе слияния null и может просто использовать 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();
1

Как вы признались раньше:

Нулевой оператор объединения (??) был добавлен как синтаксический сахар для общего случая необходимости использования троичного в сочетании с isset (). Возвращает свой первый операнд, если он существует и не равен NULL; в противном случае он возвращает свой второй операнд.

Это означает, что этот оператор работает правильно во втором блоке кода, потому что в классе b const ЧТО-ТО существует! но это недоступно. Вы не можете проверить ни существующие, ни ‘NULL-значения состояния’ существующих инкапсулированных полей с помощью ?? или с isset ().

Я предполагаю, что логика проверки инкапсулированного поля работает следующим образом:
Существует? ->да-> нулевой? -> Ошибка (не могу получить доступ к нему, чтобы проверить значение)

Другой блок кода работает как надо

0
По вопросам рекламы [email protected]