答えは、はい、文字列をコピーするということです。並べ替え...そうではありません。まあ、それはあなたの「コピー」の定義に依存します...
> = 5.4
何が起こっているかを確認するために、ソースを見てみましょう。エグゼキュータは、ここで5.5でキャストされた変数を処理します。
zend_make_printable_zval(expr, &var_copy, &use_copy);
if (use_copy) {
ZVAL_COPY_VALUE(result, &var_copy);
// if optimized out
} else {
ZVAL_COPY_VALUE(result, expr);
// if optimized out
zendi_zval_copy_ctor(*result);
}
ご覧のとおりzend_make_printable_zval()
、zvalがすでに文字列である場合、呼び出しはこれを使用して短絡します。
したがって、コピーを実行するために実行されるコードは(elseブランチ)です。
ZVAL_COPY_VALUE(result, expr);
それでは、 :の定義をZVAL_COPY_VALUE
見てみましょう。
#define ZVAL_COPY_VALUE(z, v) \
do { \
(z)->value = (v)->value; \
Z_TYPE_P(z) = Z_TYPE_P(v); \
} while (0)
それが何をしているのかに注意してください。文字列自体はコピーされません->value
( zvalのブロックに格納されます)。参照されているだけです(ポインタは同じままなので、文字列値は同じで、コピーはありません)。ただし、新しい変数(値をラップするzval部分)を作成しています。
今、私たちはzendi_zval_copy_ctor
電話に出ます。これは、内部的にそれ自体でいくつかの興味深いことを行います。ノート:
case IS_STRING:
CHECK_ZVAL_STRING_REL(zvalue);
if (!IS_INTERNED(zvalue->value.str.val)) {
zvalue->value.str.val = (char *) estrndup_rel(zvalue->value.str.val, zvalue->value.str.len);
}
break;
基本的に、これは、インターンされた文字列の場合、コピーされないことを意味します。しかし、そうでない場合は、コピーされます...では、インターンされた文字列とは何ですか、それはどういう意味ですか?
<= 5.3
5.3では、インターンされた文字列は存在しませんでした。したがって、文字列は常にコピーされます。それが本当に唯一の違いです...
ベンチマーク時間:
さて、このような場合:
$a = "foo";
$b = (string) $a;
5.4では文字列のコピーは発生しませんが、5.3ではコピーが発生します。
しかし、このような場合:
$a = str_repeat("a", 10);
$b = (string) $a;
コピーはすべてのバージョンで発生します。これは、PHPでは、すべての文字列がインターンされているわけではないためです...
ベンチマークで試してみましょう:http://3v4l.org/HEelW
$a = "foobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisoutfoobarbizbazbuztestingthisout";
$b = str_repeat("a", 300);
echo "Static Var\n";
testCopy($a);
echo "Dynamic Var\n";
testCopy($b);
function testCopy($var) {
echo memory_get_usage() . "\n";
$var = (string) $var;
echo memory_get_usage() . "\n";
}
結果:
5.4-5.5アルファ1(違いは根本的な違いをもたらさないほど小さいため、他のアルファは含まれません)
Static Var
220152
220200
Dynamic Var
220152
220520
したがって、静的変数は48バイト増加し、動的変数は368バイト増加しました。
5.3.11から5.3.22:
Static Var
624472
625408
Dynamic Var
624472
624840
静的変数は936バイト増加し、動的変数は368バイト増加しました。
したがって、5.3では、静的変数と動的変数の両方がコピーされたことに注意してください。したがって、文字列は常に複製されます。
ただし、静的文字列を使用する5.4では、zval構造のみがコピーされました。インターンされた文字列自体は同じままで、コピーされないことを意味します。
もう一つのこと
注意すべきもう一つのことは、上記のすべてが議論の余地があるということです。変数をパラメーターとして関数に渡します。次に、関数内にキャストします。したがって、コピーオンライトは回線によってトリガーされます。したがって、これを実行すると、常に(99.9%の場合)可変コピーがトリガーされます。したがって、せいぜい(インターン文字列)は、zvalの複製とそれに関連するオーバーヘッドについて話していることになります。最悪の場合、あなたは文字列の重複について話している...