(C'est plus long que je ne l'avais prévu; veuillez rester avec moi.)
La plupart des langages sont constitués de quelque chose qu'on appelle une «syntaxe»: le langage est composé de plusieurs mots-clés bien définis, et la gamme complète d'expressions que vous pouvez construire dans ce langage est construite à partir de cette syntaxe.
Par exemple, disons que vous avez un simple "langage" arithmétique à quatre fonctions qui ne prend que des entiers à un chiffre comme entrée et ignore complètement l'ordre des opérations (je vous ai dit que c'était un langage simple). Ce langage pourrait être défini par la syntaxe:
// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /
À partir de ces trois règles, vous pouvez créer n'importe quel nombre d'expressions arithmétiques à un seul chiffre. Vous pouvez alors écrire un analyseur pour cette syntaxe qui dissocient l'entrée valide dans ses types de composants ( $expression
, $number
ou $operator
) et traite le résultat. Par exemple, l'expression 3 + 4 * 5
peut être décomposée comme suit:
// 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
Nous avons maintenant une syntaxe entièrement analysée, dans notre langage défini, pour l'expression originale. Une fois que nous avons cela, nous pouvons passer par et écrire un analyseur pour trouver les résultats de toutes les combinaisons de $number $operator $number
, et cracher un résultat quand il ne nous en reste plus qu'une $number
.
Notez qu'il ne reste aucune $expression
construction dans la version analysée finale de notre expression originale. C'est parce que $expression
peut toujours être réduit à une combinaison d'autres choses dans notre langue.
PHP est à peu près le même: les constructions de langage sont reconnues comme l'équivalent de notre $number
ou $operator
. Ils ne peuvent pas être réduits à d'autres constructions linguistiques ; au lieu de cela, ce sont les unités de base à partir desquelles la langue est construite. La principale différence entre les fonctions et les constructions de langage est la suivante: l'analyseur traite directement les constructions de langage. Il simplifie les fonctions en constructions de langage.
La raison pour laquelle les constructions de langage peuvent ou non nécessiter des parenthèses et la raison pour laquelle certaines ont des valeurs de retour tandis que d'autres ne le sont pas dépend entièrement des détails techniques spécifiques de l'implémentation de l'analyseur PHP. Je ne connais pas très bien le fonctionnement de l'analyseur, donc je ne peux pas répondre spécifiquement à ces questions, mais imaginez un instant un langage qui commence par ceci:
$expression := ($expression) | ...
En effet, ce langage est libre de prendre toutes les expressions qu'il trouve et de se débarrasser des parenthèses environnantes. PHP (et ici j'emploie de pure conjecture) peut employer quelque chose de similaire pour ses constructions de langage: print("Hello")
peut être réduit print "Hello"
avant d'être analysé, ou vice-versa (les définitions de langage peuvent ajouter des parenthèses et s'en débarrasser).
C'est la raison pour laquelle vous ne pouvez pas redéfinir les constructions de langage comme echo
ou print
: elles sont effectivement codées en dur dans l'analyseur, alors que les fonctions sont mappées à un ensemble de constructions de langage et l'analyseur vous permet de modifier ce mappage à la compilation ou à l'exécution en remplacez votre propre ensemble de constructions ou d'expressions de langage.
À la fin de la journée, la différence interne entre les constructions et les expressions est la suivante: les constructions de langage sont comprises et traitées par l'analyseur. Les fonctions intégrées, bien que fournies par le langage, sont mappées et simplifiées en un ensemble de constructions de langage avant l'analyse.
Plus d'informations:
Edit: En lisant certaines des autres réponses, les gens font valoir de bons points. Parmi eux:
- Un langage intégré est plus rapide à appeler qu'une fonction. C'est vrai, ne serait-ce que marginalement, car l'interpréteur PHP n'a pas besoin de mapper cette fonction à ses équivalents intégrés au langage avant l'analyse. Sur une machine moderne, cependant, la différence est assez négligeable.
- Un langage intégré contourne la vérification des erreurs. Cela peut être vrai ou non, en fonction de l'implémentation interne de PHP pour chaque intégré. Il est certainement vrai que le plus souvent, les fonctions auront une vérification des erreurs plus avancée et d'autres fonctionnalités que les fonctions intégrées n'ont pas.
- Les constructions de langage ne peuvent pas être utilisées comme rappels de fonction. Cela est vrai, car une construction n'est pas une fonction . Ce sont des entités distinctes. Lorsque vous codez une fonction intégrée, vous ne codez pas une fonction qui prend des arguments - la syntaxe de la fonction intégrée est gérée directement par l'analyseur syntaxique et est reconnue comme une fonction intégrée plutôt que comme une fonction. (Cela peut être plus facile à comprendre si vous considérez les langages avec des fonctions de première classe: effectivement, vous pouvez passer des fonctions comme des objets. Vous ne pouvez pas faire cela avec des fonctions intégrées.)