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


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

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

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

некоторые имеют возвращаемое значение, другие нет.

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

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

4 85

4 ответа:

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

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

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

// 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 parser. Я не очень хорошо разбираюсь в том, как работает парсер, поэтому я не могу конкретно ответить на эти вопросы, но представьте себе на секунду язык, который начинается с этого:

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

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

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

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

Подробнее:

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

Edit: читая некоторые из других ответов, люди делают хорошие очки. Среди них:

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

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

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

Я понятия не имею, как это делается, но одна вещь, которую они могут сделать (из-за интеграции непосредственно в язык), - это "обойти" какой-то механизм обработки ошибок. Например, 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 core-разработчиков ; они, вероятно, знают об этом материале ^^

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

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

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

(см. Zend / zend_language_parser.y)

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

вы можете переопределить встроенные функции. Ключевые слова-это навсегда.