web-dev-qa-db-ja.com

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

PHPのprintechoの違いは何ですか?

Stack Overflowには、PHPのprintおよびechoキーワードの使用法について質問する多くの質問があります。

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

177
user187291

なぜ2つの構成体なのか?

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

違いはget_defined_functions()を印刷することで見ることができます:print関数はリストされていません。 (printfとその仲間は:printとは異なり、真の機能です。)

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

同じ理由で、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_、評価時:

  1. 単一の引数eおよび type-casts を評価し、結果の値を文字列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
_

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を使用します。

181
user187291

私は遅れていることを知っていますが、私が追加したいことの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を返すことです」と述べています。 ここ

誰かがこの振る舞いについて何らかの光を当てることができれば幸いです。

0
Mahad Ali