Я понимаю, что второй вариант позволяет избежать накладных расходов на вызов функции, но было бы интересно узнать, какой лучше из них. Я использовал unset() на протяжении большей части моего кодирования, но недавно я просмотрел несколько приличных классов, найденных в сети, которые используют $var = null вместо этого. Есть ли предпочтительный вариант, и каково его обоснование?
Ответ 1
unset() делает то, о чем говорит ее название, – удаляет переменную. Она не принуждает к немедленному освобождению памяти. Сборщик мусора PHP сделает это тогда, когда посчитает нужным, – намеренно как можно быстрее, поскольку эти циклы процессора все равно не нужны, или как можно позже, до того, как в скрипте закончится память, в зависимости от того, что произойдет раньше. Если вы делаете $whatever = null; то вы переписываете данные переменной. Вы можете освободить/сократить память быстрее, но это может забрать циклы кода в процессоре, которому они действительно нужны раньше, что приведет к увеличению общего времени выполнения. Обратите внимание, что до php5.3, если у вас есть два объекта в циклической ссылке, например, в отношениях родитель-ребенок, вызов unset() на родительском объекте не освободит память, используемую для родительской ссылки в дочернем объекте. (Также память не будет освобождена, когда родительский объект будет очищен от мусора; ошибка 33595). unset($a) также удаляет $a из таблицы символов, например:
$a = str_repeat('hello world ', 100);
unset($a);
var_dump($a);
Вывод:
Уведомление: Неизвестная переменная: a в xxx
NULL
Но когда используется $a = null:
$a = str_repeat('hello world ', 100);
$a = null;
var_dump($a);
Вывод:
NULL
Похоже, что $a = null немного быстрее, чем его аналог unset(): обновление записи в таблице символов происходит быстрее, чем ее удаление.
Когда вы попытаетесь использовать несуществующую (не установленную) переменную, возникнет ошибка, а значением для выражения переменной будет null. (Потому что, что еще должен делать PHP? Каждое выражение должно приводить к какому-то значению.)
Тем не менее, переменная с присвоенным ей null остается совершенно нормальной переменной.
Ответ 2
Выполняя unset() для переменной, вы, по сути, помечаете переменную для «сборки мусора» (в PHP его нет, но для примера), поэтому память становится недоступной. Переменная больше не содержит данных, но стек остается прежнего размера. При выполнении метода null данные исчезают, и память стека уменьшается почти сразу. Лично я использую unset() между итерациями в цикле, чтобы не было задержки, связанной с увеличением размера стека. Данные исчезают, но возникает задержка. На следующей итерации память уже занята php и, таким образом, быстрее инициализируется следующая переменная.
Ответ 3
<?php
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
$a = NULL;
}
$elapsed = microtime(true) - $start;
echo "время выполнения $elapsed в секундах\r\n";
$start = microtime(true);
for ($i = 0; $i < 10000000; $i++) {
$a = 'a';
unset($a);
}
$elapsed = microtime(true) - $start;
echo "время выполнения $elapsed в секундах\r\n";
?>
В соответствии с этим кажется, что "= null" быстрее.
Результат для PHP 5.4:
Время выполнения 0.88389301300049 в секундах
Время выполнения 2.1757180690765 в секундах
Результат дляPHP 5.3:
Время выполнения 1.7235369682312 в секундах
Время выполнения 2.9490959644318 в секундах
Результат для PHP 5.2:
Время выполнения 3.0069220066071 в секундах
Время выполнения 4.7002630233765 в секундах
Результат для PHP 5.1:
Время выполнения 2.6272349357605 в секундах
Время выполнения 5.0403649806976 в секундах
Ответ 4
Что касается объектов, особенно в сценарии ленивой загрузки, следует учитывать, что сборщик мусора работает в «холостых» циклах процессора, поэтому предположение, что у вас возникнут проблемы, когда загружается много объектов, будет решаться освобождением памяти за счет небольшого временного штрафа. Используйте time_nanosleep, чтобы позволить GC освобождать память. Желательно установить переменную в null. Протестировано на рабочем сервере, первоначально задание потребляло 50MB и затем было остановлено. После использования nanosleep постоянное потребление памяти составило 14MB. Следует сказать, что это зависит от поведения GC, которое может меняться от версии PHP к версии. Но на PHP 5.3 это работает нормально. Например, этот пример:
for($n=0; $n<count($ids); $n++) {
//unset($product); // для массивов
$product = null
if( $n % 50 == 0 ) {
// пусть GC управляет памятью
//echo "<mem>" . memory_get_usage() . "</mem>";//$ids[$n];
time_nanosleep(0, 10000000);
}
$product = $productModel->getProductSingle((int)$ids[$n],true, true, true);
...
Ответ 5
Я все еще сомневаюсь в этом коде, но я попробовал его в своем скрипте и использую xdebug, чтобы узнать, как это повлияет на использование памяти моим приложением. Скрипт установлен для моей функции следующим образом:
function gen_table_data($serv, $coorp, $type, $showSql = FALSE, $table = 'ireg_idnts') {
$sql = "SELECT COUNT(`operator`) `operator` FROM $table WHERE $serv = '$coorp'";
if($showSql === FALSE) {
$sql = mysql_query($sql) or die(mysql_error());
$data = mysql_fetch_array($sql);
return $data[0];
} else echo $sql;
}
И я добавляю unset прямо перед кодом возврата, и это дает мне 160200 циклов, затем я пытаюсь изменить его на $sql = NULL, и это дает мне 160224 циклов.
Но есть кое-что уникальное в этом сравнении, когда я не использую unset() или NULL, xdebug выдает мне 160144 циклов, как при использовании памяти.
Web