В работе с любыми данными то и дело требуется как-то обозначить их отсутствие. Новички зачастую для этой цели используют значение false, которое, по сути, является не отсутствием данных, а определённым значением типа boolean. Для того, чтобы как-то помечать неопределённость или отсутствие данных, существует специальное значение null. Про false, null и прочее уже немало сказано и добавить что-то оригинальное крайне сложно. Но гораздо сложнее бывает найти баг, вызванный неочевидным поведением этих штуковин. Поэтому, вдохновлённый одним таким багом, самым элегантным в моём послужном списке, я решил написать маленькую шпаргалку на эту тему.
Перегружать пост интересными, но довольно-таки бесполезными определениями из Википедии я не стану. Вместо этого перейду сразу к делу и приведу цитату со страницы php.net, посвящённой null:
Специальное значение NULL представляет собой переменную без значения. NULL — это единственно возможное значение типа null. Переменная считается null, если:
- ей была присвоена константа NULL.
- ей еще не было присвоено никакого значения.
- она была удалена с помощью unset().
До этого момента всё кажется простым, но чтобы так оставалось и дальше, при работе с null нужно придерживаться определённых правил.
Математические операции с null
Во всех математических операциях null ведёт себя аналогично int(0):
$a = null; $a + 1; // int(1) $a - 1; // int(-1) $a * 1; // int(0) 1 / $a; // bool(false)
Проверка переменной на null
Чтобы точно узнать, что переменная содержит null (то есть, ничего не содержит), нужно использовать либо специальную функцию is_null() либо тождественное сравнение ===, а любые другие способы не подойдут:
// Правильная проверка переменной на null $a = null; is_null($a); // bool(true) $a === null; // bool(true)
Проверка null if-выражениях, а так же в функциях empty() и isset()
Тут переменные с null ведут себя абсолютно предсказуемо, как и любые другие ложные значения (которые в if-выражениях приводятся к false). Но нужно помнить, что это не гарантирует нам, что в переменной находится именно null:
// В if-выражениях null приводится к false, как и все другие ложные значения if($a) { echo 'Sure, $a is not null!'; } else { echo 'Mabye $a is null.' } // Проверка на empty() вернёт true, но не гарантирует, что проверяемая переменная - именно null $a = null; empty($a); // bool(true) $a = []; empty($a); // bool(true) $a = ''; empty($a); // bool(true) $a = 0; empty($a); // bool(true) $a = false; empty($a); // bool(true) // Проверка isset() вернёт false не только для null, но для не определённой переменной $a = null; isset($a); // bool(false) isset($undefined); // bool(false)
Сравнение двух null
В PHP как гибкое, так и тождественное сравнение двух null всегда возвращает false, в отличие от многих других платформ, где сравнение двух неизвестностей возвращает так же неизвестность (то есть, null).
// PHP уверен, что две неизвестности равны, и даже тождественно равны $a = null; $b = null; $a == $b; // bool(true) $a === $b; // bool(true)
Поведение null при нетождественном сравнении с приведением типов данных
PHP разрешает сравнивать null-ы не только между собой, но и с другими типами данных. При этом не стоит забывать, что гибкое сравнение в php не является транзитивным, то есть, если два значения равны третьему по отдельности, не гарантирует их равенство между собой. Согласно таблицам приведения типов, гибкое сравнение null при помощи оператора == с разными значениями возвращает разные результаты:
// Для всех ложных значений гибкое сравнение с null возвращает true, кроме строки '0' $a = []; $a == null; // bool(true) $a = ''; $a == null; // bool(true) $a = 0; $a == null; // bool(true) $a = false; $a == null; // bool(true) // А при сравнении null со строкой '0' мы получим false, хотя null == false и '0' == false $a = '0'; $a == null; // bool(false) // Для всех неложных значений такое сравнение так же вернёт false $a = 1; $a == null; // bool(false) $a = '1'; $a == null; // bool(false)
Сравнение с null с помощью >, <, >=, <=, сравнение с отрицательными числами и другие заковырки
Не мне судить, насколько это является очевидным, но при сравнении с числами null всегда оказывается меньше них. Смотрите сами:
// Не смотря на то, что null == 0, он оказывается меньше любого числа null <= -1 // bool(true) null <= 0 // bool(true) null <= 1 // bool(true) !(null >= -1) // bool(true) null >= 0 // bool(true) !(null >= 1) // bool(true)
На вид ничего особенного, но из этого следует, что если в дело вмешивается null, может пройти бессмысленная, на первый взгляд, проверка:
// Из-за подобного поведения я словил однажды баг, из-за которого почти поверил в магию :) $a = null; if($a <= -1 && $a >= 0) { echo '$a <= -1 and $a >= 0 at the same time!'; }
Разное поведение null в PHP, SQL и JavaScript
А вот это, на мой взгляд, самое скверное. Реализуя логику работы с ячейками баз данных, в которых разрешено значение null, на разных этапах продвижения данных от сервера к пользователю (например, MySQL -> PHP -> JavaScript) поведение null может меняться.
Исследование null в JavaScript (а вместе с ним и загадочного undefined) заслуживает отдельной статьи. Главное отличие состоит в том, что, не смотря на приведение типов, null в JavaScript ничему не равен, кроме самого null и этого самого undefined, хотя в if-выражениях и срабатывает аналогично false. А при сравнении с числами он выдаёт ещё более забавные результаты, чем в PHP.
NULL в MySQL, к примеру, действует гораздо более прямолинейно. Он просто при любых действиях с null (даже при сравнении двух null) возвращает null. С его точки зрения, при любых действиях с неизвестностью в результате получится какая-то другая неизвестность 🙂
Простое правило при работе null, которое помогает избегать проблем
Вообще-то, не стоило читать этот пост. Держать в голове все эти нюансы, которые разные платформы трактуют по-разному, — неблагодарное занятие. Для того, чтобы избежать проблем с null нужно запомнить всего лишь одно правило:
Старайтесь не выполнять с null никаких лишних действий: не нужно его ни с чем сравнивать, складывать, сортировать. Там, где чисто теоретически переменная с null может просочиться в какие-то операторы, лучшим решением будет сперва проверить её функцией is_null().
mithrandir.ru
$var = NULL;
Что здесь случилось?
Простой: значение null
было присвоено $var
.
Да, значение null
– это значение. Регулярное, нормальное значение. null
не является логическим, а не числом, а не чем-либо еще. null
имеет тип
null
, который может принимать только одно возможное значение: null
. null
обычно используется в качестве значения-заполнителя для обозначения «нет значения». Но null
– это просто нормальное значение и тип сам по себе. Здесь ничего не видно, двигайтесь вперед.
for ($i = 0; $arr[$i] = NULL; $i++) { }
Здесь null
присваивается $arr[$i]
на первой итерации. Выражение присваивания затем возвращает назначенное значение, т. Е. ($arr[$i] = NULL)
оценивает значение null
. Затем цикл for
вычисляет этот null
чтобы решить, следует ли продолжать или нет, и поскольку значение null
считается равным
false
, оно останавливается. Результатом этого цикла является:
array(1) { [0]=> NULL }
Т.е. массив, первым и единственным индексом которого является значение null
. Ни больше ни меньше.
Если NULL .
8;е NULL имеет значение TRUE.
Это ваше единственное непонимание. Результатом выражения присваивания является назначенное значение . true
. Вот почему это работает:
$a = $b = $c;
$a
присваивается результат
$b = $c
, который равен $c
.
Во всех этих примерах вы можете заменить null
на false
для того же самого эффекта.
ruphp.com
To extend a bit on tbdavis's comment:
:: NULL == NULL is true
:: NULL == FALSE is true
:: NULL == TRUE is false
However: note the implicit type conversions that PHP performs! When using 'identical' instead of 'equal' then both NULL === FALSE and NULL === TRUE yield FALSE. An overview is easily created using something like
function evalExpr( $desc )
{
echo str_pad($desc , 15) . "--> ";
var_dump( eval( "return(" . $desc . ");" ));
}
Note that even TRUE AND TRUE does not evaluate to a boolean value, and that OR and XOR behave different as well!
PHP Version: 4.0.6
false --> bool(false)
true --> bool(true)
null --> NULL
!null --> bool(true)
true and true --> int(1)
true and false --> int(0)
true or true --> int(1)
true or false --> int(1)
true xor true --> bool(false)
true xor false --> bool(true)
true == null --> bool(false)
true === null --> bool(false)
true != null --> bool(true)
true !== null --> bool(true)
false == null --> bool(true)
false === null --> bool(false)
false != null --> bool(false)
false !== null --> bool(true)
null == null --> bool(true)
null != null --> bool(false)
null === null --> bool(true)
null !== null --> bool(false)
null or null --> int(0)
null xor null --> bool(false)
null and null --> int(0)
true or null --> int(1)
true xor null --> bool(true)
true and null --> int(0)
false or null --> int(0)
false xor null --> bool(false)
false and null --> int(0)
true < null --> bool(false)
true > null --> bool(true)
false < null --> bool(false)
false > null --> bool(false)
1 + null --> int(1)
"text" . null --> string(4) "text"
Finally, for those who do not know SQL: in SQL the NULL value is evaluated a bit like "I do not know; it could be anything, like 0, 1, a, b, true, false or even nothing at all". This implies that in SQL NULL == NULL could be interpreted as "could be anything" == "could be something else", which does not yield true! Instead, it yields NULL, which boils down to FALSE in boolean context...
Likewise, in SQL:
NULL AND TRUE yields NULL
NULL OR TRUE yields TRUE
NULL AND FALSE yields FALSE
NULL OR FALSE yields NULL
NULL == TRUE yields FALSE
NULL == FALSE yields FALSE
a.
php.svchat.ru
null
— null
. false
— false
. Грустно, но это правда.
в PHP не так много согласованности. разработчики TRY, чтобы сделать null, означает «unkown» или «несуществующий». но часто False будет служить «несуществующим» (например, strrpos ( «fail», «search» ) вернет false, а не null)
вы часто увидите, что null используется, когда они уже используют false для чего-то. например filter_input(). Они возвращают false, если переменная не работает с фильтром. и null, если переменная не существует (не существует означает, что она также не сработала с фильтром, поэтому зачем даже возвращать null?!?)
php имеет удобство возврата данных в функции. и из-за того, что разработчики записывают все виды отказа, а не данные.
И в PHP нет здравого смысла для обнаружения данных (int, str и т.д.) из отказа (false, null)
вы в значительной степени должны всегда тестировать === null или === false, в зависимости от функции. или для обоих, в таких случаях, как filter_input()/filter_var()
и здесь немного удовольствия от жонглирования типа. даже не включая массивы и объекты.
var_dump( 0<0 ); #bool(false) var_dump( 1<0 ); #bool(false) var_dump( -1<0 ); #bool(true) var_dump( false<0 ); #bool(false) var_dump( null<0 ); #bool(false) var_dump( ''<0 ); #bool(false) var_dump( 'a'<0 ); #bool(false) echo "n"; var_dump( !0 ); #bool(true) var_dump( !1 ); #bool(false) var_dump( !-1 ); #bool(false) var_dump( !false ); #bool(true) var_dump( !null ); #bool(true) var_dump( !'' ); #bool(true) var_dump( !'a' ); #bool(false) echo "n"; var_dump( false == 0 ); #bool(true) var_dump( false == 1 ); #bool(false) var_dump( false == -1 ); #bool(false) var_dump( false == false ); #bool(true) var_dump( false == null ); #bool(true) var_dump( false == '' ); #bool(true) var_dump( false == 'a' ); #bool(false) echo "n"; var_dump( null == 0 ); #bool(true) var_dump( null == 1 ); #bool(false) var_dump( null == -1 ); #bool(false) var_dump( null == false ); #bool(true) var_dump( null == null ); #bool(true) var_dump( null == '' ); #bool(true) var_dump( null == 'a' ); #bool(false) echo "n"; $a=0; var_dump( empty($a) ); #bool(true) $a=1; var_dump( empty($a) ); #bool(false) $a=-1; var_dump( empty($a) ); #bool(false) $a=false; var_dump( empty($a) ); #bool(true) $a=null; var_dump( empty($a) ); #bool(true) $a=''; var_dump( empty($a) ); #bool(true) $a='a'; var_dump( empty($a)); # bool(false) echo "n"; #new block suggested by @thehpi var_dump( null < -1 ); #bool(true) var_dump( null < 0 ); #bool(false) var_dump( null < 1 ); #bool(true) var_dump( -1 > true ); #bool(false) var_dump( 0 > true ); #bool(false) var_dump( 1 > true ); #bool(true) var_dump( -1 > false ); #bool(true) var_dump( 0 > false ); #bool(false) var_dump( 1 > true ); #bool(true)
qaru.site