2009-07-24 21 views
82

So che include, isset, require, print, echo e alcuni altri non sono funzioni ma costrutti di linguaggio.Qual è la differenza tra un costrutto di linguaggio e una funzione "built-in" in PHP?

Alcuni di questi costrutti linguistici hanno bisogno di parentesi, altri no.

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

Alcune hanno un valore di ritorno, gli altri non lo fanno.

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

Allora, qual è la differenza internatra un costrutto del linguaggio e una funzione built-in?

risposta

123

(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.)
+3

Eeeek !!! Grazie per questa bella risposta! –

+2

Ottima risposta che è abbastanza aperta da applicare a molte lingue, non solo PHP. Grazie! –

+0

Certo, molto lungo, ma wow! ne vale la pena. –

4

Dopo aver attraversato il codice, ho trovato che php analizza alcune delle istruzioni in un file yacc. Quindi sono casi speciali.

(vedi Zend/zend_language_parser.y)

A parte che non credo che ci siano altre differenze.

1

È possibile override built-in functions. Le parole chiave sono per sempre.

+0

Questa non è una funzione incorporata. È definito nell'estensione APD (Advanced PHP Debugger). –

+0

sulle funzioni di override, si potrebbe avere un bottino all'estensione del runkit (non è core, è un'estensione, quindi non risponde all'OP, ma solo a questa risposta); è molto potente e più recente di APD (e credo di aver sentito qualche tempo fa che alcune persone ci lavoravano ancora, anche se non è mostrato su pecl.php.net) –

14

I costrutti del linguaggio sono forniti dal linguaggio stesso (ad esempio istruzioni come "if", "while", ...); da qui il loro nome.

Una conseguenza di ciò è che sono più veloci a essere invocate di pre-definiti o funzioni definite dall'utente (o almeno così ho sentito/letto più volte)

Non ho idea di come è fatto, ma una cosa che possono fare (essendo integrata direttamente nella lingua) è "bypassare" una sorta di meccanismo di gestione degli errori. Ad esempio, isset() può essere utilizzato con variabili non esistenti senza causare alcun preavviso, avviso o errore.

function test($param) {} 
if (test($a)) { 
    // Notice: Undefined variable: a 
} 

if (isset($b)) { 
    // No notice 
} 

* Nota che non è il caso per i costrutti di tutte le lingue.

Un'altra differenza tra funzioni e costrutti del linguaggio è che alcuni di questi possono essere chiamati senza parentesi, come una parola chiave.

Per esempio:

echo 'test'; // language construct => OK 

function my_function($param) {} 
my_function 'test'; // function => Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING 

Anche in questo caso, non è il caso per tutti i costrutti del linguaggio.

Suppongo che non sia assolutamente possibile "disabilitare" un costrutto linguistico perché fa parte del linguaggio stesso. D'altra parte, molte funzioni PHP "integrate" non sono realmente integrate perché sono fornite da estensioni tali che sono sempre attive (ma non tutte)

Un'altra differenza è quella lingua costrutti non possono essere utilizzati come "puntatori a funzione" (voglio dire, callback, per esempio):

$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 

non ho qualsiasi altra idea venuta in mente in questo momento ... e non fare conosci molto le parti interne di PHP ...Quindi, che sarà in questo momento ^^

Se non si ottiene molto di risposte qui, forse si potrebbe chiedere questo al mailing-list Internals (vedi http://www.php.net/mailing-lists.php), dove ci sono molti PHP core-sviluppatori ; essi sono quelli che probabilmente sapere di quella roba ^^

(e sono davvero interessati dalle altre risposte, btw ^^)

Come riferimento: list of keywords and language constructs in PHP

+0

Puoi avere una funzione che accetta una not- imposta la variabile senza generare un avviso prendendo la variabile per riferimento. Questo non è limitato a costrutti linguistici come isset(). –

+0

Oh, non ci ho pensato :-(Grazie! –

Problemi correlati