(Це довше, ніж я задумав; будь ласка, терпіть зі мною.)
Більшість мов складається з чогось, що називається "синтаксисом": мова складається з декількох чітко визначених ключових слів, і весь діапазон виразів, які ви можете створити на цій мові, побудований із цього синтаксису.
Наприклад, припустимо, у вас є проста чотирифункціональна арифметична "мова", яка приймає лише одноцифрові цілі числа в якості вхідних даних і повністю ігнорує порядок операцій (я сказав вам, що це була проста мова). Цю мову можна визначити синтаксисом:
// 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
or print
: вони ефективно закодовані в парсер, тоді як функції зіставляються з набором мовних конструкцій, і парсер дозволяє вам змінити це відображення під час компіляції або виконання на підставте власний набір мовних конструкцій або виразів.
Зрештою, внутрішня різниця між конструкціями та виразами полягає в наступному: мовні конструкції розуміються та розглядаються парсером. Вбудовані функції, хоча і забезпечуються мовою, перед аналізом відображаються та спрощуються до набору мовних конструкцій.
Більше інформації:
- Форма Бекуса-Наура , синтаксис, що використовується для визначення формальних мов (yacc використовує цю форму)
Редагувати: Читаючи деякі інші відповіді, люди роблять добрі думки. Серед них:
- Вбудовану мову швидше викликати, ніж функцію. Це правда, хоча б незначно, оскільки інтерпретатору PHP не потрібно пов'язувати цю функцію зі своїми вбудованими в мову еквівалентами перед синтаксичним аналізом. Однак на сучасній машині різниця досить незначна.
- Вбудована мова обходить перевірку помилок. Це може бути і неправдою, залежно від внутрішньої реалізації PHP для кожного вбудованого. Безумовно, це правда, що найчастіше функції матимуть вдосконалену перевірку помилок та інші функції, яких вбудовані не мають.
- Конструкції мови не можна використовувати як зворотні виклики функцій. Це правда, оскільки конструкція не є функцією . Вони окремі сутності. Коли ви кодуєте вбудований файл, ви не кодуєте функцію, яка приймає аргументи - синтаксис вбудованої обробляється безпосередньо парсером і розпізнається як вбудований, а не як функція. (Це може бути простіше зрозуміти, якщо розглядати мови з першокласними функціями: ефективно, ви можете передавати функції як об'єкти. Ви не можете це робити за допомогою вбудованих.)