В чем разница между конструкцией языка и встроенной функцией в PHP?

Я знаю, что include, isset, require, print, echo, а некоторые другие не являются функциями, а языковыми конструкциями.

Некоторые из этих языковых конструкций требуют скобок, другие - нет.

require 'file.php';
isset($x);

У некоторых есть возвращаемое значение, другие - нет.

print 'foo'; //1
echo  'foo'; //no return value

Итак, что такое внутренняя разница между конструкцией языка и встроенной функцией?

Ответ 1

(Это длиннее, чем я предполагал, пожалуйста, несите меня.)

Большинство языков составлено из того, что называется синтаксисом: язык состоит из нескольких четко определенных ключевых слов, а полный набор выражений, которые вы можете построить на этом языке, создается из этого синтаксиса.

Например, скажем, у вас есть простой четырехзначный арифметический "язык", который принимает только целые числа с одной цифрой в качестве входных данных и полностью игнорирует порядок операций (я сказал вам, что это простой язык). Этот язык может быть определен синтаксисом:

// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /

Из этих трех правил вы можете построить любое число арифметических выражений с одноразрядным входом. Затем вы можете написать синтаксический анализатор для синтаксиса, который разбивает любой допустимый ввод на его типы компонентов ($expression, $number или $operator) и обрабатывает результат. Например, выражение 3 + 4 * 5 можно разбить следующим образом:

// Parentheses used for ease of explanation; they have no true syntactical meaning
$expression = 3 + 4 * 5
            = $expression $operator (4 * 5) // Expand into $exp $op $exp
            = $number $operator $expression // Rewrite: $exp -> $num
            = $number $operator $expression $operator $expression // Expand again
            = $number $operator $number $operator $number // Rewrite again

Теперь у нас есть полностью проанализированный синтаксис на нашем определенном языке для исходного выражения. После этого мы можем пройти и написать парсер, чтобы найти результаты всех комбинаций $number $operator $number, и выплюнуть результат, когда осталось только один $number.

Обратите внимание, что в окончательной анализируемой версии нашего исходного выражения нет конструкций $expression. Это потому, что $expression всегда можно свести к сочетанию других вещей на нашем языке.

PHP очень похож: языковые конструкции распознаются как эквивалент наших $number или $operator. Они не могут быть сведены к другим языковым конструкциям; вместо этого они являются базовыми единицами, из которых выстраивается язык. Ключевое различие между функциями и языковыми конструкциями таково: парсер напрямую занимается языковыми конструкциями. Это упрощает функции в языковых конструкциях.

Причина того, что языковые конструкции могут содержать или не содержать скобки, а причина имеет некоторые возвращаемые значения, а другие не зависят полностью от конкретных технических характеристик реализации парсера PHP. Я не так хорошо разбираюсь в том, как работает парсер, поэтому я не могу конкретно ответить на эти вопросы, но представьте себе второй язык, начинающийся с этого:

$expression := ($expression) | ...

Фактически, этот язык свободен принимать любые найденные выражения и избавляться от окружающих круглых скобок. PHP (и здесь я использую чистые догадки) может использовать что-то подобное для своих языковых конструкций: print("Hello") может быть уменьшено до print "Hello" до его анализа, или наоборот (определения языка могут добавлять скобки, а также устранять из них).

Это корень того, почему вы не можете переопределять языковые конструкции, такие как echo или print: они эффективно жестко закодированы в синтаксический анализатор, тогда как функции сопоставляются с набором языковых конструкций, и парсер позволяет вам измените это сопоставление во время компиляции или выполнения, чтобы заменить свой собственный набор языковых конструкций или выражений.

В конце дня внутренняя разница между конструкциями и выражениями такова: языковые конструкции понимаются и обрабатываются парсером. Встроенные функции, предоставляемые языком, сопоставляются и упрощаются до набора языковых конструкций перед разбором.

Дополнительная информация:

  • Форма Бэксу-Наура, синтаксис, используемый для определения формальных языков (yacc использует эту форму)

Изменить: Прочитав некоторые другие ответы, люди получают хорошие очки. Среди них:

  • Более сложный язык, чем функция. Это верно, если только незначительно, потому что интерпретатору PHP не нужно сопоставлять эту функцию с его эквивалентами, основанными на языке, до разбора. Однако на современной машине разница довольно незначительна.
  • Встроенный язык обходит проверку ошибок. Это может быть или не быть правдой, в зависимости от внутренней реализации PHP для каждого встроенного. Конечно, верно, что чаще всего функции будут иметь более расширенную проверку ошибок и другие функции, которые не встроены.
  • Языковые конструкции не могут использоваться как обратные вызовы функций. Это верно, потому что конструкция не является функцией, Это отдельные сущности. При кодировании встроенного кода вы не кодируете функцию, которая принимает аргументы - синтаксис встроенного обрабатывается непосредственно анализатором и распознается как встроенный, а не как функция. (Это может быть проще понять, если вы рассматриваете языки с первоклассными функциями: эффективно, вы можете передавать функции как объекты. Вы не можете делать это со встроенными функциями.)

Ответ 2

Языковые конструкции предоставляются самим языком (например, такие как "if", "while",...); отсюда их название.

Одним из следствий этого является то, что они быстрее запускаются, чем предопределенные или определяемые пользователем функции (или так я слышал/читал несколько раз)

Я понятия не имею, как это было сделано, но одна вещь, которую они могут сделать (из-за того, что она интегрирована непосредственно в langage), - это "обход" какого-то механизма обработки ошибок. Например, isset() может использоваться с несуществующими переменными без каких-либо уведомлений, предупреждений или ошибок.

function test($param) {}
if (test($a)) {
    // Notice: Undefined variable: a
}

if (isset($b)) {
    // No notice
}

* Обратите внимание, что это не так для конструкций всех языков.

Другим различием между функциями и языковыми конструкциями является то, что некоторые из них можно вызывать без скобок, например ключевое слово.

Например:

echo 'test'; // language construct => OK

function my_function($param) {}
my_function 'test'; // function => Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING

Здесь тоже не для всех языковых конструкций.

Я полагаю, что абсолютно невозможно "отключить" конструкцию языка, потому что она является частью самого языка. С другой стороны, множество "встроенных" функций PHP не являются встроенными, потому что они предоставляются расширениями, так что они всегда активны (но не все)

Другое отличие состоит в том, что языковые конструкции не могут использоваться как "указатели на функции" (например, обратные вызовы):

$a = array(10, 20);

function test($param) {echo $param . '<br />';}
array_map('test', $a);  // OK (function)

array_map('echo', $a);  // Warning: array_map() expects parameter 1 to be a valid callback, function 'echo' not found or invalid function name

У меня нет другой идеи, которая приходит мне на ум прямо сейчас... и я не очень много знаю о внутренностях PHP... Так что это будет прямо сейчас ^^

Если вы не получили здесь много ответов, возможно, вы могли бы задать это внутренним структурам рассылки (см. http://www.php.net/mailing-lists.php), где много PHP-разработчиков; это те, кто, вероятно, знал бы об этом. ^^

(И меня действительно интересуют другие ответы, btw ^^)

В качестве ссылки: список ключевых слов и языковых конструкций в PHP

Ответ 3

После прошивки кода я обнаружил, что php анализирует некоторые из операторов в файле yacc. Поэтому они являются особыми случаями.

(см. Zend/zend_language_parser.y)

Кроме того, я не думаю, что есть другие различия.