web-dev-qa-db-ja.com

$ a + ++ $ a == 2なのはなぜですか?

私がこれを試してみると:

$a = 0;    
echo $a + ++$a, PHP_EOL;
echo $a;

私はこの出力を取得します:

2
1

デモ: http://codepad.org/ncVuJtJ

何故ですか?

私はこれを出力として取得することを期待しています:

1
1

私の理解:

$a = 0;                    // a === 0    
echo $a + ++$a, PHP_EOL;   // (0) + (0+1) === 1
echo $a;                   // a === 1

しかし、なぜそれが出力ではないのですか?

65

1ではなく2を取得する理由を説明するすべての答えは実際には間違っています。 PHPのドキュメントによると、この方法で_+_と_++_を混合することは未定義の動作であるため、1または2のいずれかを取得できます。=の別のバージョンに切り替えるPHPは、得られる結果を変更する可能性があり、それは同じように有効です。

例1 を参照してください。

_// mixing ++ and + produces undefined behavior
$a = 1;
echo ++$a + $a++; // may print 4 or 5
_

ノート:

  1. 演算子の優先順位は、評価の順序を決定しません。演算子の優先順位は、式_$l + ++$l_が$l + (++$l)として解析されることのみを決定し、_+_演算子の左または右のオペランドが最初に評価されるかどうかは決定しません。左のオペランドを最初に評価すると、結果は0 + 1になり、右のオペランドを最初に評価すると、結果は1 +1になります。

  2. 演算子の結合性も評価の順序を決定しません。 _+_演算子が結合性を残したことは、_$a+$b+$c_が_($a+$b)+$c_として評価されることを決定するだけです。単一の演算子のオペランドが評価される順序は決定されません。

また、関連性があります: このバグレポート 未定義の結果を持つ別の式に関して、a PHP開発者は次のように述べています:「評価の順序については保証しません[...] 、Cがそうではないのと同じように、最初のオペランドが最初に評価されると記載されているドキュメント上の任意の場所を指すことができますか?」

112
interjay

プレインクリメント演算子「++」は、それが含まれる式の残りの部分が評価される前に実行されます。つまり、実際には次のようになります。

echo $l + ++$l; // (1) + (0+1) === 2
66
Dennis
a + b

a = 1
b = ++a

:= 2

なぜあなたは何か他のものを期待するのですか?

PHPの場合:

$a = 0;
$c = $a + ++$a;

演算子の優先順位 視覚化:

$c = ($a) + (++$a);

視覚化された評価シーケンス:

$a = 0; ($a = 0)
$a = 1; (++$a)
$c = $a + $a (1 + 1);

または書き出された:

合計演算が実行された瞬間、$aはすでに評価されているため、++$aはすでに1になっています。 ++演算子は、+演算子の前に評価されます。


楽しみのために:

$a++ + ++$a

結果も2になります。ただし、式として比較すると、等しくありません。

$a++ + ++$a == $a + ++$a

どこで

$a++ + ++$a == $a-- + --$a 

「等しい」です。


関連項目:

24
hakre

私の PHPでの評価順序 ブログ投稿でこれについて詳しく説明していますが、基本的な考え方は次のとおりです。

  • 演算子の優先順位 および結合性は評価順序とは関係ありません。
  • PHPは評価順序を保証しません。順序はPHPバージョン間で予告なしに変更される可能性があり、周囲のコードによっても異なる可能性があります。
  • 「通常」PHPは、「単純な」変数(_$a_など)へのアクセスを除いて、左から右に評価されます。単純な変数へのアクセスは実行されますafter式が実際に発生する順序に関係なく、より複雑な式。
  • この特定のケースでは、_++$a_が複雑な式であるため最初に実行され、次に_$a_の値がフェッチされることを意味します(この時点ではすでに1です)。つまり、効果的に_1 + 1 = 2_を合計していることになります。
  • 複雑な式の後に単純な変数がフェッチされる理由は、コンパイル済み変数(CV)の最適化です。 _@_エラー抑制演算子を使用するなどしてこの最適化を無効にすると、単純な変数フェッチを含め、すべての式が左から右に評価されます。
  • この特定のケースでは、最初の_1_がフェッチされ(その時点では0)、その後にのみインクリメントされるため、@($a + ++$a)は_$a_になります。
7
NikiC

++は優先順位の高い演算子であるため、最初に適用されます。

だから今l = 1.

そう 1 + 1 = 2.

6
John3136

++ $ l(プリインクリメント)を実行すると、加算の前に実行されます-> 演算子の優先順位を確認してください )。

したがって、追加する前の$lの値は1になります:

echo $l + ++$l; // $l => 1  because ++$l is done first

したがって、あなたの答えは2になります。

しかし、あなたがするとき:

echo $l // you will get your first value which is $l => 1

したがって、あなたの答えは1になります。

3
ChapMic

この動作は、PHPがスクリプトをコンパイルする方法を調べることで確認できます。例:

_$a = 0;
echo $a + ++$a;
_

次のオペコードにコンパイルされ、実行されます。

_compiled vars:  !0 = $a
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   1     0  >   ASSIGN                                                   !0, 0
         1      PRE_INC                                          $1      !0
         2      ADD                                              ~2      !0, $1
         3      ECHO                                                     ~2
         4    > RETURN                                                   null
_

これは、次の同等のスクリプトに変換されます。

_$a = 0;              // ASSIGN
$tmp = ++$a;         // PRE_INC
echo $a + $tmp;      // ADD, ECHO
_

結論

_$a_が$a + (++$a)の左側の式として評価されるまでに、_++$a_が最初に評価されたため、すでにインクリメントされています。

明らかに、この動作は 信頼されない ;そのことについてはどの言語でも。

2
Ja͢ck

インクリメントの取扱説明書を確認してください。

http://www.php.net/manual/en/language.operators.increment.php

または、次のコードパッドを参照してください: http://codepad.org/Y3CnhiLx

<?php

$n = 0;
$m = 0;
echo '++ before:';
echo $n+ ++$n;
echo PHP_EOL;
echo '++ after:';
echo $m+ $m++;
echo PHP_EOL;
echo 'n:'.$n;
echo PHP_EOL;
echo 'm:'.$m;

出力:

++ before:2
++ after:1
n:1
m:1
1
Guumaster

コードの出力はPHPバージョン ここに表示されているように

4.3.0〜5.0.5の出力
1
1

上記の場合、+演算子の左側が最初に評価されます(0、1、+)。

5.1.0-5.5.0alpha4の出力
2
1

上記の場合、+演算子の右側が最初に評価されます(1、1、+)。

これは interjayの答え に準拠していますPHPでは、部分式の評価の順序についての保証はありません。出力可能性があります1, 1は正しいので、出力1, 2である可能性があります。

1
Salman A

ご存知かもしれませんが、2つのインクリメント演算子があります。1つはプリインクリメントで、もう1つはポストインクリメントです。プレインクリメントは、式で使用する前に整数の値を増やしますが、ポストインクリメントは、式で使用した後の数値を増やします。

以下のように変数$ aと変数$ bがあるとします。

$ a = 0;

$ b = ++ $ aはb = 1の値を与えます

一方

$ b = $ a ++は値b = 0を与えます

1
kundan bora

前に述べたように、x ++と++ xには違いがあります。あなたはそれを次のように解釈することができます

x++;

セミコロンの後に増分

そして

++x;

式の評価の増分

だからあなたの表現は右から左に評価されているようです

echo $l + ++$l;
  1. $ lを取得: $ l = 0
  2. 適用++: ++ $ l = 1
  3. $ lを取得: $ l = 1
  4. 適用+ : $ l + $ l = 1 + 1 = 2
0
Tarion

最初の明らかな部分は、++の優先度が+よりも高いことです。

2番目の部分は、phpエンジンが最初のオペランドの値を別の匿名変数に格納しないことです。したがって、$l + ++$lはに相当するものではありません

$a = $l;
$b = ++$l;
return $a + $b;
0
kirilloid