mysql — несоответствие в документации PHP?

В настоящее время я читаю спецификацию PHP здесь: https://github.com/php/php-langspec

  1. Теперь я видел список-характеристическая Спецификация Вот, в котором говорится, что для список-характеристическая построить как показано ниже, правая часть простое присваивание выражение должно быть выражением, которое обозначает массив:

    список (список-выражение-списоквыбирать ) знак равно выражение

  2. Но документация список с php.net Вот, дает пример, содержащий это:

    $result = $pdo->query("SELECT id, name, salary FROM employees");
    while (list($id, $name, $salary) = $result->fetch(PDO::FETCH_NUM)) {
    //output $id, $name and $salary
    }
    

Дело в том, что PDOStatement::fetch(PDO::FETCH_NUM) возвращается FALSE если больше нет строки Но правая часть Назначение выражение должен быть массивом — и FALSE это не массив. Так что это приведет к фатальной ошибке, верно?

Я что-то пропустил в спецификации, или это действительно несоответствие?


По PHP багрепорт

7

Решение

Документация говорит следующее, где «list-intrinsic» является грамматикой, которая содержит все допустимые формы list(...) можно иметь.

list-intrinsic должен использоваться в качестве левого операнда в выражении простого присваивания, правым операндом которого должно быть выражение, обозначающее массив (называемый исходным массивом).

Что обозначает массив? Документация говорит это:

Массив — это структура данных, которая содержит набор из нуля или более элементов. Элементы массива не обязательно должны иметь один и тот же тип, и тип элемента массива может меняться в течение срока его службы.

Я думаю, что вы правы, думая, что FALSE, логическое, не квалифицируется как все, что обозначает массив как это не коллекция.

Что значит «должен» в этом контексте? Если мы прочитаем Соответствие Часть документации мы находим:

В этой спецификации «должен» должен интерпретироваться как требование к реализации или программе; и наоборот, «не должен» должен интерпретироваться как запрет.

Если требование «должен» или «не должен», которое появляется вне ограничения, нарушается, поведение не определено. Неопределенное поведение иначе указано в данной спецификации словами «неопределенное поведение» или пропуском любого явного определения поведения. Нет разницы в акценте между этими тремя; все они описывают «поведение, которое не определено».

Правильно ли вы полагаете, что должна возникать фатальная ошибка? Я думаю, что вы не правы, считая так. Если в разделе «семантика» не указано, что произойдет фатальная ошибка, отсутствие спецификации поведения или необходимость в ограничениях означает, что поведение этой части языка не определено. Это может работать. Может выдать ошибку, фатальную ошибку. Он может создать ИИ, который уничтожит всех нас, сделает Луну пурпурной или взорвет сервер. Это не определено.


Так что же происходит? Документация гласит под семантикой следующее:

Это присваивает целевым переменным ноль или более элементов исходного массива. В случае успеха он возвращает копию исходного массива. Если исходный массив на самом деле является значением NULL, это считается ошибкой, а возвращаемое значение из списка не определено.

Все элементы в исходном массиве, имеющие ключи типа string, игнорируются. Элемент, имеющий ключ int, равный 0, присваивается первой целевой переменной, элемент, имеющий ключ int, равный 1, присваивается второй целевой переменной и так далее, пока все целевые переменные не будут назначены. Любые другие элементы массива игнорируются. Если количество элементов исходного массива с ключами int меньше, чем целевых переменных, для неназначенных целевых переменных задается значение NULL и возникает нефатальная ошибка.

Тестирование дает следующие результаты:

$a = 1;
$z = FALSE;
$e = (list( $a, $b ) = $z);

var_dump($a); //NULL
var_dump($b); //NULL
var_dump($z); //FALSE

var_dump($e); //FALSE

По факту, $z = $e для любого $z кажется, даже если $z = NULL, Никакое уведомление, предупреждение или ошибка не генерируются для любого значения, которое я тестировал, если только длина исходного массива не меньше количества переменных в выражении list-intrensic. В этом случае Notice: Undefined offset Показано.

Кажется, что любое не повторяемое выражение обрабатывается так, как если бы оно было значением NULL (но это неопределенное поведение); в моей версии PHP кажется, что любое значение NULL обрезает назначение на полпути; он не будет повторяться, но выполняется предварительная часть присвоения NULL всем переменным.

Выражение while (list($id, $name, $salary) = $result->fetch(PDO::FETCH_NUM)) таким образом назначит NULL в $id, $name а также $salaryи FALSE значение завершит цикл while. Однако такое поведение не ожидается и не гарантируется спецификацией языка.

1

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

Это сделано намеренно в реализации php, чтобы разрешить этот сомнительный кусок кода:

while (list($key, $value) = each($array)) {
// ...
}

Результат each() может быть false в противном случае это вызвало бы неприятную ошибку, поэтому, хотя это поведение, по-видимому, противоречит спецификации, в основном это делается для обеспечения обратной совместимости.

Возможно, хотя и маловероятно, что следующая версия PHP отменит это поведение, но на этом этапе я бы предложил, чтобы спецификация могла быть отредактирована, чтобы отразить этот конкретный артефакт, хотя подразумеваемое неопределенное поведение также могло бы служить этой цели 🙂

Отвратительные детали

Код для этого можно найти Вот; В настоящее время выражение в правой части поддерживает:

  1. Массив,
  2. Объект, который реализует ArrayAccess,
  3. Что-то другое.

В случае «чего-то еще» его просто назначат null для всех переменных списка.

Обновить

Никита Попов предложил следующее обновление спецификации как часть тянуть запрос:

list-intrinsic должен использоваться в качестве левого операнда в выражении простого присваивания, правым операндом которого должно быть выражение, обозначающее массив или объект, реализующий ArrayAccess интерфейс (называется исходным массивом).

Этот встроенный присваивает один или несколько элементов исходного массива целевым переменным. В случае успеха он возвращает копию исходного массива. Если исходный массив не является массивом или объект реализации ArrayAccess назначения не выполняются и возвращаемое значение равно NULL.

(Изменения подчеркнуты)

6

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