PHPのprint
とecho
の違いは何ですか?
Stack Overflowには、PHPのprint
およびecho
キーワードの使用法について質問する多くの質問があります。
この投稿の目的は、PHPのprint
キーワードとecho
キーワードに関する標準的な 参照 質問と回答を提供し、それらの違いとユースケースを比較することです。
printおよびechoについての真実は、ユーザーには2つの異なる構成要素として表示されますが、基本に取りかかります。つまり、内部ソースコードを確認します。そのソースコードには、パーサーとオペコードハンドラーが含まれます。数字のゼロを表示するなどの単純なアクションを検討してください。エコーを使用するか印刷するかに関係なく、同じハンドラー「ZEND_ECHO_SPEC_CONST_HANDLER」が呼び出されます。印刷用のハンドラーは、エコー用のハンドラーを呼び出す前に1つのことを行い、次のように、印刷用の戻り値が1であることを確認します。
_ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1);
_
( ここで参照 を参照)
戻り値は、条件式でprintを使用する場合に便利です。なぜ100ではなく1なのか? Well in PHP 1または100の真実性は同じ、つまりtrueです。一方、ブール値コンテキストの0はfalse値と同等です。InPHP all non -zero値(正と負)は真実の値であり、これはPHPのPerlレガシーから派生しています。
しかし、そうだとすると、なぜechoは複数の引数を取るのか疑問に思うかもしれませんが、printは1つしか扱えません。この答えを得るには、パーサー、特にファイルzend_language_parser.yに目を向ける必要があります。 echoには柔軟性が組み込まれているため、1つまたは複数の式を出力できることに注意してください( here を参照)。一方、printは式を1つだけ出力するように制限されています( there を参照)。
Cプログラミング言語と、PHPなどの影響を受ける言語では、ステートメントと式に区別があります。構文的には、_echo expr, expr, ... expr
_はステートメントであり、_print expr
_は値に評価されるため式です。したがって、他のステートメントと同様に、_echo expr
_は独立しており、式に含めることができません。
_5 + echo 6; // syntax error
_
対照的に、_print expr
_は、単独でステートメントを形成できます。
_print 5; // valid
_
または、式の一部になります:
_ $x = (5 + print 5); // 5
var_dump( $x ); // 6
_
print
を、それが_!
_や_~
_のような単項演算子であるかのように考えたくなるかもしれませんが、演算子ではありません。 _!, ~ and print
_の共通点は、すべてがPHPに組み込まれ、それぞれが1つの引数のみを使用することです。print
を使用して、次の奇妙で有効なコードを作成できます。
_ <?php
print print print print 7; // 7111
_
一見すると、最後のprintステートメントがオペランド '7'firstを出力するという結果は奇妙に見えるかもしれません。しかし、より深く掘り下げて実際のオペコードを見ると、理にかなっています。
_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
_
生成される最初のオペコードは、「print 7」に対応するものです。 「〜0」は、値が1の一時変数です。その変数は、次の印刷オペコードのオペランドになり、一時変数を返し、プロセスが繰り返されます。最後の一時変数はまったく使用されないため、解放されます。
print
は値を返し、echo
は返さないのですか?式は値に評価されます。たとえば、_2 + 3
_は_5
_に評価され、abs(-10)
は_10
_に評価されます。 _print expr
_はそれ自体が式であるため、値を保持する必要があります。また、_1
_の一貫した値は真の結果を示し、ゼロ以外の値を返すことで式は別の値に含めるのに役立ちます表現。たとえば、このスニペットでは、printの戻り値は関数シーケンスを決定するのに役立ちます。
_<?php
function bar( $baz ) {
// other code
}
function foo() {
return print("In and out ...\n");
}
if ( foo() ) {
bar();
}
_
次の例が示すように、オンザフライでのデバッグに関しては、特定の値が表示される場合があります。
_<?php
$haystack = 'abcde';
$needle = 'f';
strpos($haystack,$needle) !== FALSE OR print "$needle not in $haystack";
// output: f not in abcde
_
補足として、一般的に、ステートメントは式ではありません。値を返しません。もちろん、例外はprintを使用する式ステートメントと、ステートメントとして使用される単純な式でさえ、_1;
_、PHP Cから継承する構文)などです。式ステートメントは奇妙に見えるかもしれませんただし、関数に引数を渡すことができるので非常に便利です。
print
は関数ですか?いいえ、それは言語構造です。すべての関数呼び出しは式ですが、関数呼び出し構文を使用しているかのように見えるビジュアルにもかかわらず、print (expr)
は式です。実際、これらの括弧は、式の評価に役立つ括弧-expr構文です。これは、式が_print "Hello, world!"
_などの単純な式である場合、オプションである場合があることを説明しています。 print (5 ** 2 + 6/2); // 28
などのより複雑な式では、括弧は式の評価に役立ちます。関数名とは異なり、 print
は構文的にはキーワード であり、意味的には "言語構成" です。
PHPの「言語構造」という用語は、通常isset
やempty
のような「疑似」関数を指します。これらの「構造」は関数とまったく同じように見えますが、実際は fexprs 、つまり、引数は評価されずに渡されるため、コンパイラからの特別な処理が必要ですprint
は、同じ方法で引数を評価することを選択するfexprです関数として。
違いはget_defined_functions()
を印刷することで見ることができます:print
関数はリストされていません。 (printf
とその仲間は:print
とは異なり、真の機能です。)
同じ理由で、thatecho(foo)
は機能します。これらの括弧は、式に関係するため、関数呼び出しの括弧とはまったく異なります。そのため、echo ( 5 + 8 )
をコーディングし、13の結果が表示されることを期待できます( reference を参照)。これらの括弧は、関数を呼び出すのではなく、式の評価に関係しています。注:if条件式、割り当てリスト、関数宣言など、PHPには括弧の他の用途があります。
print(1,2,3)
およびecho(1,2,3)
が構文エラーになるのはなぜですか?構文は_print expr
_、_echo expr
_、または_echo expr, expr, ..., expr
_です。 PHPが_(1,2,3)
_に遭遇すると、Cとは異なり、PHPには実際にはバイナリがないため、単一の式として解析しようとして失敗します。コンマ演算子;コンマはセパレータとしての役割を果たします(それでも、PHPのforループ、Cから継承した構文でバイナリコンマを見つけることができます)。
ステートメント_echo e1, e2, ..., eN;
_は、_echo e1; echo e2; ...; echo eN;
_の構文シュガーとして理解できます。
すべての式はステートメントであり、_echo e
_は常に_print e
_と同じ副作用があり、ステートメントとして使用されたときに_print e
_の戻り値は無視されるため、_echo e
_ _print e
_の構文シュガーとして。
これらの2つの観察結果は、_echo e1, e2, ..., eN;
_が_print e1; print e2; ... print eN;
_の構文糖衣と見なせることを意味します。 (ただし、以下の非セマンティックランタイムの違いに注意してください。)
したがって、print
のセマンティクスのみを定義する必要があります。 _print e
_、評価時:
e
および type-casts を評価し、結果の値を文字列s
に評価します。 (したがって、_print e
_はprint (string) e
と同等です。)s
を 出力バッファ にストリーミングします(最終的には標準出力にストリーミングされます)。1
_に評価します。print
には、戻り変数(擬似コード)を設定するための小さなオーバーヘッドが含まれます
_print 125;
PRINT 125,$temp ; print 125 and place 1 in $temp
UNSET $temp ; remove $temp
_
single echo
は1つのオペコードにコンパイルします:
_echo 125;
ECHO 125
_
複数値echo
は複数のオペコードにコンパイルします
_echo 123, 456;
ECHO 123
ECHO 456
_
複数値echo
は引数を連結せず、1つずつ出力することに注意してください。
参照: _zend_do_print
_ 、 _zend_do_echo
_ .
_ZEND_PRINT
_ は次のように実装されます(擬似コード)
_PRINT var, result:
result = 1
ECHO var
_
したがって、基本的に_1
_を結果変数に入れ、実際のジョブを_ZEND_ECHO
_ハンドラーに委任します。 _ZEND_ECHO
_ は以下を行います
_ECHO var:
if var is object
temp = var->toString()
zend_print_variable(temp)
else
zend_print_variable(var)
_
ここで、zend_print_variable()
は実際の「印刷」を実行します(実際には、専用のSAPI関数にリダイレクトするだけです)。
echo x
_ vs _print x
_echoとは異なり、printは一時変数を割り当てます。ただし、このアクティビティに費やされる時間はごくわずかであるため、これら2つの言語構造の違いはごくわずかです。
echo a,b,c
_ vs _echo a.b.c
_最初のステートメントは、3つの別個のステートメントにコンパイルされます。 2番目は式_a.b.c.
_全体を評価し、結果を出力してすぐに破棄します。連結にはメモリの割り当てとコピーが含まれるため、最初のオプションの方が効率的です。
Webアプリケーションでは、出力はほとんどテンプレートに集中しています。テンプレートはecho
のエイリアスである_<?=
_を使用するため、コードの他の部分でもecho
に固執することは論理的に思えます。 echo
には、複数の式を連結せずに印刷できるという追加の利点があり、一時的な戻り変数を設定するオーバーヘッドがありません。したがって、echo
を使用します。
私は遅れていることを知っていますが、私が追加したいことの1つは、私のコードにあることです
$stmt = mysqli_stmt_init($connection) or echo "error at init";
エラー「構文エラー、予期しない「エコー」(T_ECHO)」が発生します
ながら
$stmt = mysqli_stmt_init($connection) or print "error at init";
正常に動作します。
Echoに関するドキュメントには、「echo(他の言語構成要素とは異なり)は関数のようには動作しません」と書かれています hereここ 。だから私は理由がわかりません。また、エコーと印刷に関するドキュメントでは、「エコーの主な違いは、印刷は単一の引数のみを受け入れ、常に1を返すことです」と述べています。 ここ
誰かがこの振る舞いについて何らかの光を当てることができれば幸いです。