(Questo è più lungo del previsto,
La maggior parte delle lingue sono costituite da una "sintassi": la lingua è composta da diverse parole chiave ben definite e dalla gamma completa di espressioni che è possibile costruire in quel linguaggio è costruito da quella sintassi.
Ad esempio, supponiamo di avere un semplice "linguaggio" aritmetico a quattro funzioni che prende solo numeri interi a una sola cifra come input e ignora completamente l'ordine delle operazioni (ti ho detto che era un linguaggio semplice). Quel linguaggio potrebbe essere definita dalla sintassi:
// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /
Da queste tre regole, si può costruire qualsiasi numero di cifre-ingresso singolo espressioni aritmetiche. È quindi possibile scrivere un parser per questa sintassi che analizza qualsiasi input valido nei suoi tipi di componente ($expression
, $number
o $operator
) e gestisce il risultato. Ad esempio, l'espressione 3 + 4 * 5
può essere suddiviso come segue:
// 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
Ora abbiamo una sintassi completamente analizzata, nella nostra lingua definita, per l'espressione originale. Una volta che abbiamo questo, possiamo passare e scrivere un parser per trovare i risultati di tutte le combinazioni di $number $operator $number
e sputare un risultato quando ne rimane uno solo $number
.
Prendere nota che non ci sono costrutti $expression
rimasti nella versione finale analizzata della nostra espressione originale. Questo perché $expression
può sempre essere ridotto a una combinazione di altre cose nella nostra lingua.
PHP è lo stesso: i costrutti di linguaggio sono riconosciuti come equivalenti al nostro $number
o $operator
. Loro non possono essere ridotti in altri costrutti di linguaggio; invece, sono le unità di base da cui viene costruita la lingua. La differenza chiave tra funzioni e costrutti del linguaggio è questa: il parser si occupa direttamente con i costrutti del linguaggio. Semplifica le funzioni in costrutti linguistici.
Il motivo per cui il linguaggio costruisce può richiedere o meno le parentesi e il motivo per cui alcuni hanno valori di ritorno mentre altri non dipendono interamente dai dettagli tecnici specifici dell'implementazione del parser PHP. Non sono così ben versato nel modo in cui funziona il parser, quindi non posso rispondere a queste domande in particolare, ma immaginate per un attimo un linguaggio che inizia con questo:
$expression := ($expression) | ...
In effetti, questo linguaggio è libero di prendi tutte le espressioni che trova e sbarazzati delle parentesi che circondano.PHP (e qui sto usando puro lavoro di supposizione) può impiegare qualcosa di simile per i suoi costrutti linguistici:può essere ridotto a print "Hello"
prima di essere analizzato, o viceversa (le definizioni di lingua possono aggiungere parentesi e sbarazzarsi di esse).
Questa è la radice del motivo per cui non è possibile ridefinire costrutti del linguaggio come echo
o print
: stanno efficacemente insita nel parser, mentre le funzioni vengono abbinate ad una serie di costrutti del linguaggio e il parser consente di modificare che la mappatura in fase di compilazione o di runtime per sostituire il proprio insieme di costrutti o espressioni del linguaggio.
Alla fine della giornata, la differenza interna tra costrutti ed espressioni è questa: i costrutti del linguaggio sono compresi e gestiti dal parser. Le funzioni integrate, fornite dalla lingua, vengono mappate e semplificate in un insieme di costrutti linguistici prima dell'analisi.
Maggiori informazioni:
- Backus-Naur form, la sintassi utilizzata per definire linguaggi formali (yacc utilizza questo modulo)
Edit: Leggendo alcune delle altre risposte, le persone fanno buoni punti . Tra questi:
- Un linguaggio incorporato è più veloce da chiamare di una funzione. Questo è vero, se non marginalmente, perché l'interprete PHP non ha bisogno di mappare quella funzione ai suoi equivalenti incorporati nel linguaggio prima di analizzare. Su una macchina moderna, tuttavia, la differenza è abbastanza trascurabile.
- Un linguaggio incorporato ignora il controllo degli errori. Questo può o non può essere vero, a seconda dell'implementazione interna di PHP per ogni builtin. È certamente vero che il più delle volte le funzioni avranno un controllo degli errori più avanzato e altre funzionalità che i builtin non hanno.
- I costrutti di linguaggio non possono essere utilizzati come callback delle funzioni. Questo è vero, perché un costrutto è non una funzione. Sono entità separate. Quando si codifica un builtin, non si sta codificando una funzione che accetta argomenti - la sintassi del builtin viene gestita direttamente dal parser e viene riconosciuta come built-in, piuttosto che come funzione. (Questo può essere più facile da capire se si considerano le lingue con funzioni di prima classe: efficacemente, è possibile passare le funzioni come oggetti. Non è possibile farlo con i builtin.)
Eeeek !!! Grazie per questa bella risposta! –
Ottima risposta che è abbastanza aperta da applicare a molte lingue, non solo PHP. Grazie! –
Certo, molto lungo, ma wow! ne vale la pena. –