У чому різниця між мовною конструкцією та “вбудованою” функцією в PHP?


92

Я знаю , що include, isset, require, print, echo, і деякі інші не є функціями , але мовні конструкції.

Деякі з цих мовних конструкцій потребують дужок, інші - ні.

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

Деякі мають повернене значення, інші - ні.

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

То яка внутрішня різниця між мовною конструкцією та вбудованою функцією?

Відповіді:


131

(Це довше, ніж я задумав; будь ласка, терпіть зі мною.)

Більшість мов складається з чогось, що називається "синтаксисом": мова складається з декількох чітко визначених ключових слів, і весь діапазон виразів, які ви можете створити на цій мові, побудований із цього синтаксису.

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

// 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"як він буде проаналізований, або навпаки (визначення мов можуть додавати дужки, а також позбуватися від них).

Це корінь того, чому ви не можете перевизначити мовні конструкції, такі як echoor print: вони ефективно закодовані в парсер, тоді як функції зіставляються з набором мовних конструкцій, і парсер дозволяє вам змінити це відображення під час компіляції або виконання на підставте власний набір мовних конструкцій або виразів.

Зрештою, внутрішня різниця між конструкціями та виразами полягає в наступному: мовні конструкції розуміються та розглядаються парсером. Вбудовані функції, хоча і забезпечуються мовою, перед аналізом відображаються та спрощуються до набору мовних конструкцій.

Більше інформації:

  • Форма Бекуса-Наура , синтаксис, що використовується для визначення формальних мов (yacc використовує цю форму)

Редагувати: Читаючи деякі інші відповіді, люди роблять добрі думки. Серед них:

  • Вбудовану мову швидше викликати, ніж функцію. Це правда, хоча б незначно, оскільки інтерпретатору PHP не потрібно пов'язувати цю функцію зі своїми вбудованими в мову еквівалентами перед синтаксичним аналізом. Однак на сучасній машині різниця досить незначна.
  • Вбудована мова обходить перевірку помилок. Це може бути і неправдою, залежно від внутрішньої реалізації PHP для кожного вбудованого. Безумовно, це правда, що найчастіше функції матимуть вдосконалену перевірку помилок та інші функції, яких вбудовані не мають.
  • Конструкції мови не можна використовувати як зворотні виклики функцій. Це правда, оскільки конструкція не є функцією . Вони окремі сутності. Коли ви кодуєте вбудований файл, ви не кодуєте функцію, яка приймає аргументи - синтаксис вбудованої обробляється безпосередньо парсером і розпізнається як вбудований, а не як функція. (Це може бути простіше зрозуміти, якщо розглядати мови з першокласними функціями: ефективно, ви можете передавати функції як об'єкти. Ви не можете це робити за допомогою вбудованих.)

2
Чудова відповідь, яка досить відкрита, щоб застосувати її до багатьох мов, а не лише до PHP. Дякую!
Леві Ботельо

15

Конструкції мови забезпечуються самою мовою (наприклад, інструкції типу "якщо", "в той час як", ...); звідси їх назва.

Одним із наслідків цього є те, що їх швидше викликати, ніж заздалегідь визначені або визначені користувачем функції (або я вже чув / читав кілька разів)

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


Ви можете мати функцію, яка приймає не встановлену змінну, не генеруючи повідомлення, беручи змінну за посиланням. Це не обмежується мовними конструкціями, такими як isset ().
Tom Haigh

О, не думав про це :-( Дякую!
Паскаль МАРТІН

4

Пробравшись по коду, я виявив, що php аналізує деякі твердження у файлі yacc. Тож це особливі випадки.

(див. Zend / zend_language_parser.y)

Окрім цього, я не думаю, що є інші відмінності.


1

Ви можете замінити вбудовані функції . Ключові слова назавжди.


Це не вбудована функція. Визначається у розширенні APD (Advanced PHP Debugger).
Ionuț G. Stan

щодо перевизначення функцій, ви можете отримати бабло на розширенні runkit (це теж не основне, це розширення, тому не відповідає на OP, а лише на цю відповідь); він справді потужний і недавніший, ніж APD (і, я вважаю, я чув якийсь час тому, що деякі люди все ще працювали над цим, навіть якщо це не показано на pecl.php.net)
Паскаль МАРТІН
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.