リファレンス:PHPの印刷とエコーの比較


182

PHPの違いは何であるprintとはecho

Stack Overflowには、PHP printechoキーワードの使用について多くの質問があります。

この投稿の目的は、 PHP とキーワードに関する標準的な参照質問と回答を提供し、それらの違いとユースケースを比較することです。printecho


3
ここでは、印刷の戻り値については十分ではないと思います。印刷は、高速なデバッグ出力またはそのようなものに便利です:strpos($ x、$ y)!== FALSE OR print "something"。入力が速く、読みやすい。そして、「関数を出力する」は何らかの理由で読むのが面倒でした(あなたの議論は...奇妙で明白ではないようです)-それは言語構造です。
XzKto 2011

1
これをオープンに保つためにここで行う必要があるのは次のとおりです。1。質問と回答に分割します。2.スタックオーバーフローの主題に関する既存のコンテンツへの参照/リンク(ここでは少し似ています:stackoverflow.com/questions/3737139/…)ですが、答えは含まれています。3. CWである必要があります。
ケブ

「関連コラム」は結構ですが、あまり焦点が絞られていません。正規の参照質問および回答としての価値を高めるには、十分に調査する必要があり、他の特定の適切な回答へのリンクは価値を追加します。
ケブ

質問は本当に実際の質問である必要があります。完了したら、正規部分に関するバナーを追加できます。
Tim Post

回答:


185

なぜ2つの構造なのですか?

印刷エコーの真実は、ユーザーには2つの異なる構成要素として表示されますが、基本、つまり内部ソースコードを見ると、どちらも実際にはエコーの陰影です。そのソースコードには、パーサーとオペコードハンドラーが含まれます。数字の0を表示するなどの単純なアクションを考えます。エコーと印刷のどちらを使用しても、同じハンドラ「ZEND_ECHO_SPEC_CONST_HANDLER」が呼び出されます。printのハンドラーは、echoのハンドラーを呼び出す前に1つのことを行います。これは、次のように、printの戻り値が1であることを確認します。

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

参考のためにここを参照してください

条件式でprintを使用したい場合、戻り値は便利です。なぜ100ではなく1なのですか?PHPでは、1または100の真実性は同じ、つまり真ですが、ブール値のコンテキストでの0は偽の値と同等です。PHPでは、ゼロ以外のすべての値(正と負)は真の値であり、これはPHPのPerlレガシーに由来します。

しかし、これが当てはまる場合、echoが複数の引数を取るのに、printは1つの引数しか処理できないのに不思議に思うかもしれません。この回答では、パーサー、特にzend_language_parser.yファイルを参照する必要があります。エコーには、1つまたは複数の式を出力できるように柔軟性が組み込まれていることに注意してください(ここを参照)。一方、printは1つの式のみを印刷するように制限されています(そこを参照)。

構文

Cプログラミング言語およびPHPのようなCプログラミング言語によって影響を受ける言語では、ステートメントと式に違いがあります。構文的に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に組み込まれており、それぞれが一つだけ引数を取るということです。を使用printして、次の奇妙で有効なコードを作成できます。

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

一見すると、最後のprintステートメントがそのオペランド「7」を最初に出力するという結果は奇妙に見えるかもしれません。しかし、深く掘り下げて実際のオペコードを見ると、理にかなっています。

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表現自体は、それは値を保持する必要があり、それは、一貫した値を行い1truthy結果を示し、式が別の式に含めるために有用となるゼロ以外の値を返すこと。たとえば、次のスニペットでは、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)関数呼び出し構文を使用しているかのように見えるビジュアルにもかかわらず、すべての関数呼び出しは式ですが、式です。実際には、これらの括弧は括弧式の式であり、式の評価に役立ちます。これは、式がのような単純なものである場合、オプションとなる場合があることを説明していprint "Hello, world!"ます。print (5 ** 2 + 6/2); // 28括弧などのより複雑な式では、式の評価に役立ちます。関数名とprint異なり、は構文的にはキーワードであり、意味的には「言語構造」です。

PHPの「言語構造」という用語は、通常、issetまたはのような「疑似」関数を指しemptyます。これらの「構文」は関数とまったく同じに見えますが、実際にはfexprsです。つまり、引数は評価されずに渡されます。これには、コンパイラーによる特別な処理が必要です。printたまたま関数と同じ方法で引数を評価することを選択するfexprです。

違いは印刷によって確認できます。リストされている機能get_defined_functions()はありませんprint。(とはいえprintf、友達とは:とは異なりprint、真の機能です。)

なぜprint(foo)が機能するのですか?

それが機能するのと同じ理由でecho(foo)。これらの括弧は、式に関係するため、関数呼び出しの括弧とはかなり異なります。そのため、コーディングecho ( 5 + 8 )を行うと13の結果が表示されることが期待できます(参照を参照)。これらの括弧は、関数を呼び出すのではなく、式の評価に関与します。注:if条件式、代入リスト、関数宣言など、PHPのかっこの使用法は他にもあります。

なぜprint(1,2,3)echo(1,2,3)構文エラーになりますか?

構文はprint exprecho exprまたはecho expr, expr, ..., exprです。PHPはに遭遇すると(1,2,3)、それを単一の式として解析しようとして失敗します。これは、Cとは異なり、PHPには実際には2項カンマ演算子がないためです。コンマは区切り文字としてより役立ちます。(それでも、PHPのforループ、Cから継承された構文では、バイナリコンマが見つかるかもしれません。)

意味論

このステートメントecho e1, e2, ..., eN;は、の構文糖として理解できますecho e1; echo e2; ...; echo eN;

すべての式はステートメントであり、echo e常にと同じ副作用がありprint eprint eステートメントとして使用した場合、の戻り値は無視されるためecho e、の構文シュガーとして理解できprint eます。

これらの2つの観察は、のecho e1, e2, ..., eN;構文糖と見なすことができることを意味しますprint e1; print e2; ... print eN;。(ただし、以下の非セマンティックランタイムの違いに注意してください。)

したがって、のセマンティクスを定義するだけで済みますprintprint e、評価時:

  1. 単一の引数eを評価し、結果の値を文字列に型キャストしますs。(したがって、print eと同等print (string) eです。)
  2. 文字列s出力バッファーにストリーミングします(最終的には標準出力にストリーミングされます)。
  3. 整数に評価し1ます。

バイトコードレベルでの違い

print 戻り値の変数(疑似コード)を設定するための小さなオーバーヘッドが含まれます

print 125;

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

シングルはecho、1つのオペコードにコンパイルします。

echo 125;

ECHO 125

複数値echoが複数のオペコードにコンパイルされます

echo 123, 456;

ECHO 123
ECHO 456

複数値echoは引数を連結しませんが、1つずつ出力します。

リファレンス:zend_do_printzend_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)

where zend_print_variable()は実際の「印刷」を実行します(実際には、専用のSAPI関数にリダイレクトするだけです)。

スピード:echo xvsprint x

echoとは異なり、printは一時変数を割り当てます。ただし、このアクティビティに費やされる時間はごくわずかであるため、これら2つの言語構造の違いはごくわずかです。

スピード:echo a,b,cvsecho a.b.c

最初のものは、3つの個別のステートメントにコンパイルされます。2番目は、式全体を評価しa.b.c.、結果を出力して、すぐに破棄します。連結にはメモリの割り当てとコピーが含まれるため、最初のオプションの方が効率的です。

どちらを使用するのですか?

Webアプリケーションでは、出力は主にテンプレートに集中します。テンプレートは使用するため<?=の別名である、echo論理的に固執すると思われるechoだけでなく、コードの他の部分で。echo複数の式を連結せずに出力できるという追加の利点があり、一時的な戻り変数を生成するオーバーヘッドがありません。したがって、を使用しますecho


5
これを広範囲に編集および明確化し、セマンティクスに関するセクションを追加しました。私はそれには自信がありますが、誰かがそれを再確認することができました。
jameshfisher 2013

1
これは、echo $a,$b,$c文字列変数の連結に使用する方が良いという意味ですか?正直なところ、これが使用されているのを見たことがありません。
geoff 2013

1
機能の違いを説明するTL; DRセクションはどうですか?のように:print1つの引数のみを許可し、echo複数の引数を持つことができます。echocan printとreturnの間、式の一部になることはできません...; いくつかのパフォーマンスの要約があるかもしれません。そして、それらすべての「なぜ」および「ボンネットの下」の部分
YakovL

0

私は遅れていることを知っていますが、追加したいことの1つは私のコードにあることです

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

「構文エラー、予期しない「エコー」(T_ECHO)」というエラーが発生する

ながら

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

正常に動作します。

エコーに関するドキュメントには、「エコー(他の言語構造とは異なり)は関数のように動作しない」とあります が、印刷ドキュメントについては、「印刷は実際には実際の関数ではありません(言語構造です)」とあります。だから私はなぜだかわかりません。また、echoとprint docsについては、「echoとの主な違いは、printは単一の引数しか受け入れず、常に1を返すことです。」ここに

誰かがこの行動についていくつかの光を当てることができれば幸いです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.