Référence: Comparaison de l'impression et de l'écho de PHP


182

Quelle est la différence entre PHP printet echo?

Stack Overflow a de nombreuses questions sur l'utilisation de PHP printet des echomots clés.

Le but de cet article est de fournir une question de référence canonique et une réponse sur PHP printet les echomots-clés et de comparer leurs différences et leurs cas d'utilisation.


3
Je pense que ce n'est pas assez sur la valeur de retour d'impression. Print est utile pour une sortie de débogage rapide ou quelque chose comme ça: strpos ($ x, $ y)! == FALSE OU print "something". Rapide à taper et bon à lire. Et "Est-ce que imprimer une fonction" était difficile à lire pour une raison quelconque (votre argumentation semble ... étrange et pas évidente) - c'est une construction de langage, il y a bien pire chose que vous ne pouvez pas faire avec: les fonctions variables.
XzKto

1
Pour garder cela ouvert, ce qui doit être fait ici est: 1. divisé en une question et une réponse. 2. Référence / lien vers le contenu existant sur le sujet sur Stack Overflow (un peu comme ici: stackoverflow.com/questions/3737139/… ) mais dans la réponse. 3. Doit être CW.
Kev

La "colonne associée" est bien, mais elle n'est pas très ciblée. Pour augmenter sa valeur en tant que question et réponse de référence canoniques, elle doit également être bien documentée et des liens vers d'autres bonnes réponses spécifiques ajouteraient de la valeur.
Kev

La question doit vraiment être une question réelle . Je peux y ajouter une bannière concernant la partie canonique une fois que vous avez terminé.
Tim Post

Réponses:


185

Pourquoi deux constructions?

La vérité à propos de l' impression et de l' écho est que, bien qu'ils apparaissent aux utilisateurs comme deux constructions distinctes, ils sont tous les deux vraiment des nuances d'écho si vous revenez à l'essentiel, c'est-à-dire regardez le code source interne. Ce code source implique l'analyseur ainsi que les gestionnaires d'opcode. Considérez une action simple telle que l'affichage du nombre zéro. Que vous utilisiez echo ou print, le même gestionnaire "ZEND_ECHO_SPEC_CONST_HANDLER" sera appelé. Le gestionnaire pour print fait une chose avant d'appeler le gestionnaire pour echo, il s'assure que la valeur de retour pour print est 1, comme suit:

ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1);

(voir ici pour référence )

La valeur de retour est une commodité si l'on souhaite utiliser print dans une expression conditionnelle. Pourquoi 1 et pas 100? Eh bien, en PHP, la véracité de 1 ou 100 est la même, c'est-à-dire vraie, alors que 0 dans un contexte booléen équivaut à une valeur fausse. En PHP, toutes les valeurs non nulles (positives et négatives) sont des valeurs de vérité et cela dérive de l'héritage Perl de PHP.

Mais, si tel est le cas, alors on peut se demander pourquoi echo prend plusieurs arguments alors que print ne peut en gérer qu'un. Pour cette réponse, nous devons nous tourner vers l'analyseur, en particulier le fichier zend_language_parser.y . Vous noterez que l'écho a la flexibilité intégrée de sorte qu'il puisse imprimer une ou plusieurs expressions (voir ici ). tandis que print est contraint d'imprimer une seule expression (voir ici ).

Syntaxe

Dans le langage de programmation C et les langages influencés par celui-ci tels que PHP, il y a une distinction entre les instructions et les expressions. Syntaxiquement, echo expr, expr, ... exprest une instruction tandis que print exprest une expression puisqu'elle s'évalue à une valeur. Par conséquent, comme d'autres déclarations, echo exprest autonome et est incapable d'inclure dans une expression:

5 + echo 6;   // syntax error

En revanche,, print exprpeut à lui seul former une déclaration:

print 5; // valid

Ou, faites partie d'une expression:

   $x = (5 + print 5); // 5 
   var_dump( $x );     // 6 

On pourrait être tenté de penser printque c'était un opérateur unaire, comme !ou ~cependant ce n'est pas un opérateur. Ce qui !, ~ and printa en commun, c'est qu'ils sont tous intégrés à PHP et chacun ne prend qu'un seul argument. Vous pouvez utiliser printpour créer le code étrange mais valide suivant:

    <?php 
    print print print print 7; // 7111

À première vue , le résultat peut sembler étrange que la dernière instruction d'impression imprime son opérande de « 7 » abord . Mais, si vous creusez plus profondément et regardez les opcodes réels, cela a du sens:

line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   3     0  >   PRINT                                            ~0      7
         1      PRINT                                            ~1      ~0
         2      PRINT                                            ~2      ~1
         3      PRINT                                            ~3      ~2
         4      FREE                                                     ~3
         5    > RETURN                                                   1

Le tout premier opcode généré est celui correspondant au 'print 7'. Le '~ 0' est une variable temporaire dont la valeur est 1. Cette variable devient un opérande pour le prochain opcode d'impression qui à son tour renvoie une variable temporaire et le processus se répète. La dernière variable temporaire n'est pas du tout utilisée, elle est donc libérée.

Pourquoi printrenvoie- t-il une valeur et echonon?

Les expressions s'évaluent en valeurs. Par exemple, 2 + 3évalue à 5et abs(-10)évalue à 10. Puisqu'elle print exprest elle-même une expression, elle doit contenir une valeur et c'est le cas, une valeur cohérente de 1indique un résultat véridique et en renvoyant une valeur non nulle, l'expression devient utile pour être incluse dans une autre expression. Par exemple, dans cet extrait de code, la valeur de retour de print est utile pour déterminer une séquence de fonctions:

<?php

function bar( $baz ) { 
   // other code   
}
function foo() {
  return print("In and out ...\n");
}

if ( foo() ) {

     bar();
}

Vous pouvez trouver l'impression d'une valeur particulière lorsqu'il s'agit de déboguer à la volée, comme l'illustre l'exemple suivant:

<?php
$haystack = 'abcde';
$needle = 'f';
strpos($haystack,$needle) !== FALSE OR print "$needle not in $haystack"; 

// output: f not in abcde

En remarque, en général, les déclarations ne sont pas des expressions; ils ne renvoient pas de valeur. L'exception, bien sûr, sont les instructions d'expression qui utilisent des expressions print et même des expressions simples utilisées comme instruction, comme 1;une syntaxe dont PHP hérite de C. L'instruction d'expression peut sembler étrange mais elle est très utile, permettant de passer des arguments à les fonctions.

Est-ce printune fonction?

Non, c'est une construction de langage. Bien que tous les appels de fonction soient des expressions, print (expr)c'est une expression, malgré le visuel qui semble utiliser la syntaxe d'appel de fonction. En vérité, ces parenthèses sont une syntaxe parenthèses-expr, utile pour l'évaluation des expressions. Cela explique le fait qu'ils sont parfois facultatifs si l'expression est simple, comme print "Hello, world!". Avec une expression plus complexe telle que print (5 ** 2 + 6/2); // 28les parenthèses, aide à l'évaluation de l'expression. Contrairement aux noms de fonction, printest syntaxiquement un mot-clé et sémantiquement une «construction de langage» .

Le terme «construction de langage» en PHP fait généralement référence à des «pseudo» fonctions comme issetou empty. Bien que ces "constructions" ressemblent exactement à des fonctions, ce sont en fait des fexprs , c'est-à-dire que les arguments leur sont passés sans être évalués, ce qui nécessite un traitement spécial de la part du compilateur. printse trouve être une fexpr qui choisit d'évaluer son argument de la même manière qu'une fonction.

La différence se voit en imprimant get_defined_functions(): aucune printfonction n'est répertoriée. (Bien printfque les amis le soient: contrairement print, ce sont de vraies fonctions.)

Pourquoi print (foo) fonctionne-t-il alors?

Pour la même raison qui echo(foo)fonctionne. Ces parenthèses sont très différentes des parenthèses d'appel de fonction car elles concernent plutôt des expressions. C'est pourquoi on peut coder echo ( 5 + 8 )et s'attendre à ce qu'un résultat de 13 s'affiche (voir référence ). Ces parenthèses sont impliquées dans l'évaluation d'une expression plutôt que dans l'appel d'une fonction. Remarque: il existe d'autres utilisations des parenthèses en PHP, telles que les expressions if-conditionnelles, les listes d'affectations, les déclarations de fonctions, etc.

Pourquoi print(1,2,3)et echo(1,2,3)entraîner des erreurs de syntaxe?

La syntaxe est print expr, echo exprou echo expr, expr, ..., expr. Lorsque PHP rencontre (1,2,3), il essaie de l'analyser comme une seule expression et échoue, car contrairement à C, PHP n'a pas vraiment d'opérateur virgule binaire; la virgule sert plutôt de séparateur. (Vous pouvez néanmoins trouver une virgule binaire dans les boucles for de PHP, syntaxe héritée de C.)

Sémantique

La déclaration echo e1, e2, ..., eN;peut être comprise comme du sucre syntaxique pour echo e1; echo e2; ...; echo eN;.

Étant donné que toutes les expressions sont des instructions et ont echo etoujours les mêmes effets secondaires que print e, et que la valeur de retour de print eest ignorée lorsqu'elle est utilisée comme une instruction, nous pouvons la comprendre echo ecomme du sucre syntaxique pour print e.

Ces deux observations signifient que cela echo e1, e2, ..., eN;peut être considéré comme du sucre syntaxique pour print e1; print e2; ... print eN;. (Cependant, notez les différences d'exécution non sémantiques ci-dessous.)

Il suffit donc de définir la sémantique pour print. print e, une fois évalué:

  1. évalue son argument unique eet convertit le type de la valeur résultante en une chaîne s. (Ainsi, print eéquivaut à print (string) e.)
  2. Diffuse la chaîne svers le tampon de sortie (qui sera éventuellement diffusé vers la sortie standard).
  3. S'évalue à l'entier 1.

Différences au niveau du bytecode

print implique une petite surcharge de remplissage de la variable de retour (pseudocode)

print 125;

PRINT  125,$temp     ; print 125 and place 1 in $temp 
UNSET  $temp         ; remove $temp

single echocompile en un opcode:

echo 125;

ECHO 125

multi-valeur echocompile en plusieurs opcodes

echo 123, 456;

ECHO 123
ECHO 456

Notez que multi-valeur echone concatène pas ses arguments, mais les génère un par un.

Référence: zend_do_print, zend_do_echo.

Différences d'exécution

ZEND_PRINT est implémenté comme suit (pseudocode)

PRINT  var, result:

    result = 1
    ECHO var

Donc, il place essentiellement 1la variable de résultat et délègue le travail réel au ZEND_ECHOgestionnaire. ZEND_ECHOfait ce qui suit

ECHO var:

    if var is object
        temp = var->toString()
        zend_print_variable(temp)
    else
        zend_print_variable(var)

zend_print_variable()effectue la véritable "impression" (en fait, il ne fait que rediriger vers une fonction SAPI dédiée).

Vitesse: echo xvsprint x

Contrairement à echo , print alloue une variable temporaire. Cependant, le temps consacré à cette activité est minime, donc la différence entre ces deux constructions linguistiques est négligeable.

Vitesse: echo a,b,cvsecho a.b.c

Le premier se compose de trois déclarations distinctes. Le second évalue l'expression entière a.b.c., imprime le résultat et le supprime immédiatement. La concaténation impliquant des allocations de mémoire et des copies, la première option sera plus efficace.

Alors lequel utiliser?

Dans les applications Web, la sortie est principalement concentrée dans les modèles. Étant donné que les modèles utilisent <?=, qui est l'alias de echo, il semble logique de s'en tenir également à echod'autres parties du code. echoprésente un avantage supplémentaire de pouvoir imprimer plusieurs expressions sans les concaténer et n'implique pas une surcharge de remplissage d'une variable de retour temporaire. Alors, utilisez echo.


5
J'ai largement édité et clarifié cela, et ajouté une section sur la sémantique. J'en suis assez confiant, mais quelqu'un pourrait le vérifier.
jameshfisher

1
Cela signifie-t-il donc qu'il vaut mieux l'utiliser echo $a,$b,$cpour la concaténation de chaînes de caractères vars? Honnêtement, je n'ai jamais vu cela en cours d'utilisation.
geoff

1
Que diriez-vous d'une section TL; DR décrivant les différences fonctionnelles? Comme: printn'autorise qu'un seul argument, echopeut en avoir plusieurs; echone peut pas faire partie d'une expression tandis que printcan et retourne ...; et peut-être un résumé des performances. Et toutes ces parties "pourquoi" et "sous le capot" après
YakovL

0

Je sais que je suis en retard mais une chose que je voudrais ajouter est que dans mon code

 $stmt = mysqli_stmt_init($connection) or echo "error at init"; 

donne une erreur "erreur de syntaxe, 'écho' inattendu (T_ECHO)"

tandis que

 $stmt = mysqli_stmt_init($connection) or print "error at init";

fonctionne très bien.

Docs about echo dit que "echo (contrairement à d'autres constructions de langage) ne se comporte pas comme une fonction" ici, mais à propos de print, docs dit aussi "print n'est pas réellement une fonction réelle (c'est une construction de langage)" ici . Alors je ne sais pas pourquoi. Et aussi à propos de l'écho et des documents d'impression, il est dit: "Les principales différences avec echo sont que print n'accepte qu'un seul argument et renvoie toujours 1." ici

Je serais heureux si quelqu'un pouvait faire la lumière sur ce comportement.

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.