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, ... expr
est une instruction tandis que print expr
est une expression puisqu'elle s'évalue à une valeur. Par conséquent, comme d'autres déclarations, echo expr
est autonome et est incapable d'inclure dans une expression:
5 + echo 6; // syntax error
En revanche,, print expr
peut à 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 print
que c'était un opérateur unaire, comme !
ou ~
cependant ce n'est pas un opérateur. Ce qui !, ~ and print
a en commun, c'est qu'ils sont tous intégrés à PHP et chacun ne prend qu'un seul argument. Vous pouvez utiliser print
pour 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 print
renvoie- t-il une valeur et echo
non?
Les expressions s'évaluent en valeurs. Par exemple, 2 + 3
évalue à 5
et abs(-10)
évalue à 10
. Puisqu'elle print expr
est elle-même une expression, elle doit contenir une valeur et c'est le cas, une valeur cohérente de 1
indique 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 print
une 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); // 28
les parenthèses, aide à l'évaluation de l'expression. Contrairement aux noms de fonction, print
est 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 isset
ou 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. print
se 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 print
fonction n'est répertoriée. (Bien printf
que 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 expr
ou 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 e
toujours les mêmes effets secondaires que print e
, et que la valeur de retour de print e
est ignorée lorsqu'elle est utilisée comme une instruction, nous pouvons la comprendre echo e
comme 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é:
- évalue son argument unique
e
et convertit le type de la valeur résultante en une chaîne s
. (Ainsi, print e
équivaut à print (string) e
.)
- Diffuse la chaîne
s
vers le tampon de sortie (qui sera éventuellement diffusé vers la sortie standard).
- 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 echo
compile en un opcode:
echo 125;
ECHO 125
multi-valeur echo
compile en plusieurs opcodes
echo 123, 456;
ECHO 123
ECHO 456
Notez que multi-valeur echo
ne 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 1
la variable de résultat et délègue le travail réel au ZEND_ECHO
gestionnaire. ZEND_ECHO
fait ce qui suit
ECHO var:
if var is object
temp = var->toString()
zend_print_variable(temp)
else
zend_print_variable(var)
où zend_print_variable()
effectue la véritable "impression" (en fait, il ne fait que rediriger vers une fonction SAPI dédiée).
Vitesse: echo x
vsprint 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,c
vsecho 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 à echo
d'autres parties du code. echo
pré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
.