Ответ 1
Ответ: да, он копирует строку. Сортировка... Не совсем. Ну, это зависит от вашего определения "copy"...
>= 5.4
Чтобы узнать, что происходит, взгляните на источник. Исполнитель обрабатывает переменную cast в 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 alpha 1 (не включая другие альфы, поскольку различия незначительны, чтобы не иметь принципиального значения)
Static Var 220152 220200 Dynamic Var 220152 220520
Таким образом, статический var увеличился на 48 байт, а динамический var увеличился на 368 байт.
-
5.3.11 - 5.3.22:
Static Var 624472 625408 Dynamic Var 624472 624840
Статический var увеличился на 936 байт, а динамический var увеличился на 368 байт.
Поэтому обратите внимание, что в 5.3 скопированы как статические, так и динамические переменные. Таким образом, строка всегда дублируется.
Но в 5.4 со статическими строками была скопирована только структура zval. Это означает, что сама строка, которая была интернирована, остается неизменной и не копируется...
Одна другая вещь
Еще одно замечание: все вышеперечисленное является спорным. Вы передаете переменную в качестве параметра функции. Затем вы выполняете функцию. Таким образом, копирование на запись будет вызвано вашей линией. Так что запуск, который всегда (ну, в 99,9% случаев) вызывает переменную копию. Так что в лучшем случае (интернированные строки) вы говорите о дублировании zval и связанных с этим накладных расходах. В худшем случае вы говорите о дублировании строк...