(Dies ist länger als beabsichtigt; bitte tragen Sie es mit mir.)
Die meisten Sprachen bestehen aus einer sogenannten "Syntax": Die Sprache besteht aus mehreren genau definierten Schlüsselwörtern, und der gesamte Ausdrucksbereich, den Sie in dieser Sprache erstellen können, wird aus dieser Syntax aufgebaut.
Nehmen wir zum Beispiel an, Sie haben eine einfache arithmetische "Sprache" mit vier Funktionen, die nur einstellige Ganzzahlen als Eingabe verwendet und die Reihenfolge der Operationen vollständig ignoriert (ich habe Ihnen gesagt, dass es sich um eine einfache Sprache handelt). Diese Sprache könnte durch die Syntax definiert werden:
// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /
Aus diesen drei Regeln können Sie eine beliebige Anzahl von einstelligen arithmetischen Eingaben erstellen. Anschließend können Sie einen Parser für diese Syntax , dass bricht jede gültige Eingabe in seine Komponententypen (schreiben $expression
, $number
oder $operator
) und beschäftigt sich mit dem Ergebnis. Beispielsweise kann der Ausdruck 3 + 4 * 5
wie folgt unterteilt werden:
// 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
Jetzt haben wir eine vollständig analysierte Syntax in unserer definierten Sprache für den ursprünglichen Ausdruck. Sobald wir dies haben, können wir einen Parser schreiben, um die Ergebnisse aller Kombinationen von zu finden $number $operator $number
, und ein Ergebnis ausspucken, wenn wir nur noch eines $number
haben.
Beachten Sie, dass $expression
in der endgültigen analysierten Version unseres ursprünglichen Ausdrucks keine Konstrukte mehr vorhanden sind . Das liegt daran, dass $expression
sich unsere Sprache immer auf eine Kombination anderer Dinge reduzieren lässt.
PHP ist ähnlich: Sprachkonstrukte werden als das Äquivalent unserer erkannt $number
oder$operator
. Sie können nicht auf andere Sprachkonstrukte reduziert werden ; Stattdessen sind sie die Basiseinheiten, aus denen die Sprache aufgebaut ist. Der Hauptunterschied zwischen Funktionen und Sprachkonstrukten besteht darin, dass der Parser sich direkt mit Sprachkonstrukten befasst. Es vereinfacht Funktionen zu Sprachkonstrukten.
Der Grund, warum Sprachkonstrukte Klammern erfordern oder nicht, und der Grund, warum einige Rückgabewerte haben, während andere nicht vollständig von den spezifischen technischen Details der PHP-Parser-Implementierung abhängen. Ich bin nicht so gut mit der Funktionsweise des Parsers vertraut, daher kann ich diese Fragen nicht speziell beantworten, aber stellen Sie sich für eine Sekunde eine Sprache vor, die damit beginnt:
$expression := ($expression) | ...
Tatsächlich kann diese Sprache alle gefundenen Ausdrücke verwenden und die umgebenden Klammern entfernen. PHP (und hier verwende ich reine Vermutungen) verwendet möglicherweise etwas Ähnliches für seine Sprachkonstrukte:print("Hello")
möglicherweise auf reduziertprint "Hello"
bevor es analysiert wird, oder umgekehrt (Sprachdefinitionen können Klammern hinzufügen und sie entfernen).
Dies ist die Wurzel dafür, warum Sie Sprachkonstrukte wie nicht neu definieren können echo
oderprint
: Sie sind effektiv im Parser fest codiert, während Funktionen einer Reihe von Sprachkonstrukten zugeordnet sind und der Parser es Ihnen ermöglicht, diese Zuordnung zur Kompilierungs- oder Laufzeit auf zu ändern Ersetzen Sie Ihre eigenen Sprachkonstrukte oder Ausdrücke.
Letztendlich besteht der interne Unterschied zwischen Konstrukten und Ausdrücken darin, dass Sprachkonstrukte vom Parser verstanden und behandelt werden. Integrierte Funktionen werden, obwohl sie von der Sprache bereitgestellt werden, vor dem Parsen einer Reihe von Sprachkonstrukten zugeordnet und vereinfacht.
Mehr Info:
- Backus-Naur-Form , die Syntax zur Definition formaler Sprachen (yacc verwendet diese Form)
Bearbeiten: Beim Lesen einiger anderer Antworten machen die Leute gute Punkte. Unter ihnen:
- Eine eingebaute Sprache ist schneller aufzurufen als eine Funktion. Dies ist, wenn auch nur am Rande, der Fall, da der PHP-Interpreter diese Funktion vor dem Parsen nicht seinen in die Sprache integrierten Entsprechungen zuordnen muss. Bei einer modernen Maschine ist der Unterschied jedoch vernachlässigbar gering.
- Eine eingebaute Sprache umgeht die Fehlerprüfung. Dies kann zutreffen oder nicht, abhängig von der internen PHP-Implementierung für jedes eingebaute Gerät. Es ist sicherlich richtig, dass Funktionen häufig über eine erweiterte Fehlerprüfung und andere Funktionen verfügen, die integrierte Funktionen nicht bieten.
- Sprachkonstrukte können nicht als Funktionsrückrufe verwendet werden. Dies ist wahr, weil ein Konstrukt keine Funktion ist . Sie sind getrennte Einheiten. Wenn Sie eine integrierte Funktion codieren, codieren Sie keine Funktion, die Argumente akzeptiert. Die Syntax der integrierten Funktion wird direkt vom Parser verarbeitet und als integrierte Funktion und nicht als Funktion erkannt. (Dies ist möglicherweise leichter zu verstehen, wenn Sie Sprachen mit erstklassigen Funktionen betrachten: Sie können Funktionen effektiv als Objekte weitergeben. Mit integrierten Funktionen können Sie dies nicht tun.)