Разница между неустановленным и = нулевым

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

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

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

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

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

Techno Mumbo Jumbo не является ответом.

6 ответов

Решение

Важное различие между обоими методами заключается в том, что 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() коллега. Кажется, что обновление записи таблицы символов происходит быстрее, чем ее удаление.

добавление

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

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 байт, но, тем не менее, это разница.

При использовании unset использование памяти и время обработки меньше.

http://php.net/manual/en/function.unset.php

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

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

ноль

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

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

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

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

Это зависит от вашей скорости и потребностей в данных, например, чтение большого массива из memcache/ или DB только для того, чтобы взять часть данных и поместить их в другой, гораздо меньший массив подмножеств, может быть хорошим кандидатом на нулевое значение, потому что в противном случае вы можете в конечном итоге хранение всех этих других данных до завершения функции, которая может накапливаться и вызывать 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;
            }

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

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

Рассматривая простой класс, подобный этому:

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 метод работает быстрее.

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

$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

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

Разница в том, что присваивание нулевого значения является присвоением нулевого значения, а не деинициализацией. Если вы не работаете над критической проблемой производительности, вы отключите использование unset, если вы проверяете обе возможности на своей версии PHP. Основное отличие произошло с PHP 7.4 и типами свойств, вы можете отменить свойство, не допускающее значение null, но вы не можете назначить значение null.

      class C {
    public int $value;
}

$c = new C();
var_dump(isset($c->value));   // false
$c->value = 5;
var_dump($c->value);          //5
unset($c->value);
//var_dump($c->value);       //Error: Typed property C::$value must not be accessed before initialization
var_dump(isset($c->value));  // false
$c->value = 5;
$c->value = null;            //Error Typed property C::$value must be int, null used

https://3v4l.org/VUVD1

Другие вопросы по тегам