У чому різниця між мовною конструкцією та “вбудованою” функцією в 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.