Почему парсер PHP понимает "$ x ++ - ++ $x", но не удается "$ x +++++ $x"?
У меня есть движок, который выполняет некоторые математические и логические операции, беря формулы, операнды и операторы из файла.
Все операции выполняются в области eval
, а окончательный результат сохраняется в другом файле.
Эти файлы часто передаются через сеть, поэтому я пытаюсь свести их к минимуму, разделив все пробелы до и после операций.
Насколько я знаю, в этом нет строгих правил, однако я наткнулся на это поведение:
$x = 1;
$result = $x++-++$x; // works
$result = $x+++++$x; // fails
$result = $x++ + ++$x; // works again
-
Почему PHP путают синтаксис "+++++", но принимает "++ - ++"? Как
"плюс" лучше, чем "минус"?
-
Есть ли какой-либо список операторов, которые чувствительны
о пробелах?
Ответы
Ответ 1
Парсер PHP ищет знак ++
перед последним знаком +
, а синтаксис ($x++)++
не имеет смысла, из-за того, что оператор приращения должен применяться к переменной (а не к целое число, которое является результатом первого $x++
).
Приоритет операций оператора можно найти здесь:
http://php.net/manual/en/language.operators.precedence.php
$x+++++$x;
^ php parser starts here, find $x++
^ here there is a new ++, which has hight precedence to the next + char
^ here is the last +, which the php parser will find last.
Когда два ++
, ++
разделяются знаком минус, код фактически $x++ - ++$x
, тот, который может понять парсер PHP.
Это также причина, по которой работает $x++ + ++$x
.
Ответ 2
Ответ заключается в том, что синтаксический анализатор ищет более длинные токены перед поиском более коротких. Поэтому ++++++ становится ++ ++ +, что является непонятным для интерпретатора.
PHP является одним из многих языков, который заимствует грамматику выражения из C, поэтому эта заметка может вас заинтересовать. В проект C11, раздел 6.4, пункт 6 привел пример:
фрагмент программы x +++++ y анализируется как x ++ ++ + y, что нарушает ограничение на операторы приращения, даже если синтаксический анализ x ++ + ++ y может привести к правильному выражению.
Ответ 3
Более подробная информация. Когда PHP script "лексируется", то есть когда он сканируется, проверяются токены, содержащие script. Пара символов типа "++" обозначает токен приращения, как показано ниже:
<ST_IN_SCRIPTING>"++" {
RETURN_TOKEN(T_INC);
}
Это "правило" находится в файле Zend/language_scanner.l, который сопровождает PHP при загрузке и установке. Единственный способ, которым a script при сканировании становится понятным для лексера в отношении переменных до или после инкремента, - это если есть какая-то демаркация, такая как интервал, чтобы каждый "+" был правильно оценен в контексте.
Обратите внимание, что писать код, подобный приведенному ниже, нецелесообразен:
<?php
$x=0;
echo $x++ + ++$x;
даже он будет правильно лексироваться. Причина возражения против этого стиля кодирования заключается в том, что он может быть менее очевидным для человеческого мозга относительно того, что действительно происходит. Порядок оценки - это не то, что может показаться, то есть переменная, подлежащая поэтапному увеличению, а затем добавленная к ней с ее предварительно увеличенным значением.
В соответствии с opcodes, до и после инкремента происходят до добавления. Также обратите внимание, что post-incrementation возвращает значение переменной, а затем увеличивает его. Таким образом, изначально $x присваивается значение 0. Затем оно увеличивается после того, как временная переменная возвращается с нулевым значением. Затем значение $x увеличивается, чтобы получить значение единицы. Далее, $x предварительно увеличивается, и поэтому $x перемещается со значения от одного до двух, а его временная переменная оценивается как два. Наконец, добавляются две временные переменные, так что 0 + 2 == 2
; см. здесь, а также здесь.
Кроме того, отличный читать здесь.
Кстати, в этом случае PHP соответствует своему языку программирования C C; см. здесь.