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


92

Je sais que include, isset, require, print, echo, et d'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 pas.

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?

Réponses:


131

(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, $numberou $operator) et traite le résultat. Par exemple, l'expression 3 + 4 * 5peut ê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 $expressionconstruction dans la version analysée finale de notre expression originale. C'est parce que $expressionpeut 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 $numberou $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 echoou 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:

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

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.)

2
Excellente réponse qui est suffisamment ouverte pour s'appliquer à de nombreux langages, pas seulement à PHP. Je vous remercie!
Levi Botelho

15

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 à être appelées que les fonctions prédéfinies ou définies par l'utilisateur (ou alors j'ai entendu / lu plusieurs fois)

Je n'ai aucune idée de comment c'est fait, mais une chose qu'ils peuvent faire (parce qu'ils sont intégrés directement dans le langage) est de "contourner" une sorte de mécanisme de gestion des erreurs. Par exemple, isset () peut être utilisé avec des variables non existantes 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 tous les langages.

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 parce qu'elle fait partie du langage lui-même. Par contre, de nombreuses fonctions PHP "intégrées" ne sont pas vraiment intégrées car elles sont fournies par des extensions telles qu'elles sont toujours actives (mais pas toutes)

Une autre différence est que les constructions de langage ne peuvent pas être utilisées comme des "pointeurs de fonction" (je veux dire, des 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 pour le moment ... et je ne sais pas grand-chose sur les internes de PHP ... Donc ça va être tout de suite ^^

Si vous n'obtenez pas beaucoup de réponses ici, peut-être pourriez-vous 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; ce sont eux qui sauraient probablement ce genre de choses ^^

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

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


Vous pouvez avoir une fonction qui accepte une variable non définie sans générer d'avis en prenant la variable par référence. Cela ne se limite pas aux constructions de langage comme isset ().
Tom Haigh

Oh, je n'y ai pas pensé :-( Merci!
Pascal MARTIN

4

Après avoir parcouru le code, j'ai trouvé que php analysait certaines des déclarations 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.


1

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


Ce n'est pas une fonction intégrée. Est défini dans l'extension APD (Advanced PHP Debugger).
Ionuț G. Stan

à propos des fonctions de remplacement, vous pourriez avoir un butin sur l'extension runkit (ce n'est pas non plus le noyau, c'est une extension, donc ne répond pas à l'OP, mais seulement à cette réponse); c'est vraiment puissant, et plus récent qu'APD (et je crois avoir entendu il y a quelque temps que des gens y travaillaient encore, même si ce n'est pas montré sur pecl.php.net)
Pascal MARTIN
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.