web-dev-qa-db-fra.com

Quelle est la différence entre une construction de langage et une fonction "intégrée" en PHP?

Je sais que include, isset, require, print, echo, et quelques autres ne sont pas des fonctions mais des constructions de langage.

Certaines de ces constructions de langage nécessitent des parenthèses, d'autres non.

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

Certains ont une valeur de retour, d'autres non.

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

Alors, quelle est la différence interne entre une construction de langage et une fonction intégrée?

91
Philippe Gerber

(C'est plus long que je ne le pensais; veuillez faire preuve de patience.)

La plupart des langues sont composées de quelque chose appelé une "syntaxe": la langue est composée de plusieurs mots-clés bien définis, et la gamme complète d'expressions que vous pouvez construire dans cette langue est constituée à partir de cette syntaxe.

Par exemple, supposons que vous ayez un "langage" arithmétique simple à quatre fonctions qui ne prend en entrée que des entiers à un chiffre 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 chiffre. Vous pouvez ensuite écrire un analyseur pour cette syntaxe qui décompose toute entrée valide en 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 parcourir et écrire un analyseur pour trouver les résultats de toutes les combinaisons de $number $operator $number, Et cracher un résultat lorsqu'il ne nous reste qu'un $number.

Notez qu'il ne reste plus de constructions $expression Dans la version finale analysée de notre expression d'origine. 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 dans d'autres constructions de langage ; ce sont plutôt 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 dépend pas entièrement des détails techniques spécifiques de l'implémentation de l'analyseur PHP PHP. Je ne suis pas que bien familiarisé avec le fonctionnement de l'analyseur, je ne peux donc pas répondre à ces questions spécifiquement, mais imaginez une seconde une langue 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 une pure conjecture) peut utiliser quelque chose de similaire pour ses constructions de langage: print("Hello") pourrait être réduit à print "Hello" Avant d'être analysé , ou vice-versa (les définitions de langage peuvent ajouter des parenthèses et les supprimer).

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, tandis que les fonctions sont mappées à un ensemble de constructions de langage et l'analyseur vous permet de modifier ce mappage lors de la compilation ou de l'exécution pour remplacer 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 à un ensemble de constructions de langage avant l'analyse.

Plus d'informations:

  • forme Backus-Naur , la syntaxe utilisée pour définir les langages formels (yacc utilise cette forme)

Edit: En lisant certaines des autres réponses, les gens font de bons arguments. Parmi eux:

  • Un langage intégré est plus rapide à appeler qu'une fonction. Cela est vrai, ne serait-ce que de manière marginale, 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 ou peut ne pas être vrai, en fonction de l'implémentation interne PHP pour chaque buildin. 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 builtins non.
  • Les constructions de langage ne peuvent pas être utilisées comme rappels de fonctions. C'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 et est reconnue comme une fonction intégrée, plutôt qu'une fonction. (Cela peut être plus facile à comprendre si vous considérez les langages avec des fonctions de première classe: en fait, vous pouvez passer des fonctions comme des objets. Vous ne pouvez pas le faire avec des fonctions intégrées.)
129
Tim

Les constructions de langage sont fournies par le langage lui-même (comme des instructions comme "if", "while", ...); d'où leur nom.

Une conséquence de cela est qu'elles sont plus rapides à invoquer que les fonctions prédéfinies ou définies par l'utilisateur (ou alors j'ai entendu/lu plusieurs fois)

Je ne sais pas comment c'est fait, mais une chose qu'ils peuvent faire (en raison de leur intégration directe dans le langage) est de "contourner" une sorte de mécanisme de gestion des erreurs. Par exemple, isset () peut être utilisé avec des variables inexistantes sans provoquer de notification, d'avertissement ou d'erreur.

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

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

* Notez que ce n'est pas le cas pour les constructions de toutes les langues.

Une autre différence entre les fonctions et les constructions de langage est que certaines d'entre elles peuvent être appelées sans parenthèses, comme un mot-clé.

Par exemple :

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

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

Ici aussi, ce n'est pas le cas pour toutes les constructions de langage.

Je suppose qu'il n'y a absolument aucun moyen de "désactiver" une construction de langage car elle fait partie du langage lui-même. D'un autre côté, beaucoup de fonctions "intégrées" PHP les fonctions ne sont pas vraiment intégrées car elles sont fournies par des extensions telles qu'elles sont toujours actives (mais pas toutes eux)

Une autre différence est que les constructions de langage ne peuvent pas être utilisées comme "pointeurs de fonction" (je veux dire, les rappels, par exemple):

$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

Je n'ai aucune autre idée qui me vient à l'esprit en ce moment ... et je ne sais pas grand-chose sur les internes de PHP ... Donc ce sera tout de suite ^^

Si vous n'obtenez pas beaucoup de réponses ici, vous pourriez peut-être demander ceci aux internes de la liste de diffusion (voir http: // www .php.net/mailing-lists.php ), où il y a beaucoup de développeurs PHP core; ce sont eux qui seraient probablement au courant de tout ça ^^

(Et je suis vraiment intéressé par les autres réponses, btw ^^)

Comme référence: liste de mots-clés et de constructions de langage en PHP

15
Pascal MARTIN

Après avoir parcouru le code, j'ai constaté que php analyse certaines des instructions dans un fichier yacc. Ce sont donc des cas particuliers.

(voir Zend/zend_language_parser.y)

En dehors de cela, je ne pense pas qu'il y ait d'autres différences.

4
terminus

Vous pouvez remplacer les fonctions intégrées . Les mots-clés sont éternels.

1
Jason S