Разница между unset и = null

Из случайный пост php.net:

Если вы делаете $whatever = null; то вы переписываете переменную данные. Вы могли бы освободить память/сократить быстрее, но она может украсть CPU циклов из кода, который действительно нуждается в них раньше, в результате чего более длительное время выполнения.

По-видимому, это бесспорная истина поэтому, возможно, кто-то будет так любезен объяснить.

Я имею в виду, что, unset магически не выполняет какие-либо команды сборки, тогда как $whatever = null; делает? Ответ, как указано, примерно так же полезен, как сказать

$any = null сбрасывает буфер и кеш L1, тогда как unset очищает буфер и сбрасывает кеш L2.

Техно mumbo jumbo не является ответом.

Ответ 1

Важным отличием обоих методов является то, что unset($a) также удаляет $a из таблицы символов; например:

$a = str_repeat('hello world ', 100);
unset($a);
var_dump($a);

Выходы:

Notice: Undefined variable: a in xxx
NULL

Но когда используется $a = null:

$a = str_repeat('hello world ', 100);
$a = null;
var_dump($a);

Выходы:

NULL

Я также запускал код с помощью теста и обнаружил, что $a = null примерно на 6% быстрее, чем его аналог unset(). Кажется, что обновление записи таблицы символов происходит быстрее, чем удаление.

Добавление

Другим отличием (как видно из этого небольшого script), является то, сколько памяти восстанавливается после каждого вызова:

echo memory_get_usage(), PHP_EOL;
$a = str_repeat('hello world ', 100);
echo memory_get_usage(), PHP_EOL;
// EITHER unset($a); OR $a = null;
echo memory_get_usage(), PHP_EOL;

При использовании unset() возвращаются все, кроме 64 байт памяти, тогда как $a = null; освобождает все, кроме 272 байта памяти. У меня недостаточно знаний, чтобы знать, почему существует разница в 208 байтов между обоими методами, но это тем не менее.

Ответ 3

Я сделал простой тест.

Учитывая простой класс:

class Cat{
    public $eyes  = 2;
    public $claws = 4;
    public $name  = "Kitty";
    public $sound = ['Meow', 'Miaou'];
}

Я запускаю этот код

$start = microtime(true);

for($i = 10000000; $i > 0; --$i){
    $cat = new Cat;
    $cat = null;
}

$end = microtime(true);

printf("Run in %s and use %s memory",
        round($end - $start, 2), round(memory_get_usage() / 1000, 2));

Запуск в 1.95 и использование 233.29 памяти

И этот

for($i = 10000000; $i > 0; --$i){
    $cat = new Cat;
    unset($cat);
}

Запуск в 2.28 и использование 233.1 памяти

Для чего кажется, что метод null работает быстрее.

Ответ 4

Приведенные выше ответы великолепны, особенно комментарий: "Важное различие между обоими методами заключается в том, что unset ($ a) также удаляет $ a из таблицы символов".

Тем не менее, я не думаю, что кто-то действительно полностью ответил на вопрос в практическом смысле, потому что они не описывают, как они используются. Хорошо, я думаю, мы знаем, что они в основном делают одно и то же. Зачем использовать один над другим?

ноль

Немедленно восстанавливает память (за счет увеличения времени), несмотря на то, что PHP самостоятельно управляет памятью/сборкой мусора.

снята с охраны()

Обычно рекомендуется, так как он восстанавливает память "когда я смогу к ней добраться" и поэтому считается более быстрым, так как не выделяет ему ресурсы сразу.

Когда следует использовать null против unset?

Базовые массивы данных (небольших данных) и т.д. Являются хорошими кандидатами для сброса, поскольку память не станет проблемой. Большие наборы данных и/или где-либо необходимость немедленного восстановления памяти лучше для нуля. Например, такие большие запросы к базе данных могут очень быстро уничтожить ваш потолок памяти PHP, если он вызывается несколько раз в функции и т.д., Что приведет к ошибкам страницы 500 из-за переполнения памяти и т.д. Поэтому, если важна скорость (или вообще, следует предпочитать unset).) и когда мало заботы о наращивании памяти.

Пример: Взятие большого массива и помещение его в MemCache:

            list($inv1, $inv2, $inv3, $inv4) = array_chunk($inventory_array), 
            ceil(count($val['inventory']) / 4));
            MemCache::set($cacheKeyInv1, $inv1, $expiry);
            MemCache::set($cacheKeyInv2, $inv2, $expiry);
            MemCache::set($cacheKeyInv3, $inv3, $expiry);
            MemCache::set($cacheKeyInv4, $inv4, $expiry);
            for ($i = 1; $i < 5; $i++) {
                ${"inv" . $i} = null; // why not use unset ?
            }

Цикл for очищает данные, можно использовать null или unset, но, поскольку это большой набор данных, возможно, null предпочтительнее, поскольку он быстрее восстанавливает память.

Ответ 5

Используя код

$a = str_repeat('hello world ', 10000);

$start1 = microtime(true);
unset($a);
$stop1 = microtime(true);

$a = str_repeat('hello world ', 10000);

$start2 = microtime(true);
$a = null;
$stop2 = microtime(true);

echo 'unset time lap of '. ( $stop1 - $start1 ) .'<br>';
echo 'null time lap of '. ( $stop2 - $start2 ) .'<br>';

в течение 10 раз:

unset time lap of 5.0067901611328E-6
null time lap of 1.1920928955078E-6

unset time lap of 9.5367431640625E-7
null time lap of 9.5367431640625E-7

unset time lap of 0
null time lap of 9.5367431640625E-7

unset time lap of 2.1457672119141E-6
null time lap of 1.1920928955078E-6

unset time lap of 2.1457672119141E-6
null time lap of 0

unset time lap of 9.5367431640625E-7
null time lap of 0

unset time lap of 1.9073486328125E-6
null time lap of 9.5367431640625E-7

unset time lap of 9.5367431640625E-7
null time lap of 0

unset time lap of 1.9073486328125E-6
null time lap of 9.5367431640625E-7

unset time lap of 0
null time lap of 0

Похоже, что нулевое присвоение имеет меньшее время обработки.