20 неожиданностей в php, о которых знают не все
Содержание:
- Изменение типа данных в ключах массива
- Пример использования сессии
- Что такое сессия в PHP?
- Увеличение строки ++
- Introduction
- Все объекты в PHP передаются по ссылке
- Ключевое слово revert#
- Удаляем повторяющиеся элементы массива в PHP
- Closure::call — вызов анонимной функции с указанием контекста
- Null Оператор ??
- Странное поведение в PHP при передаче значения foreach по ссылке
- Как удалить пустые элементы из массива?
- Точное сравнение
- empty() и объекты
- Ключевое слово initial#
- Что же в Java Enterprise?
- Разница между PHP операторами OR и ||, AND и &&
- Proposal
- В чем отличие между функциями isset(), empty() и is_null() в PHP?
- in_array() нас обманывает
- Обзор функций isset(), empty() и is_null() в PHP
Изменение типа данных в ключах массива
При создании индекса массива PHP автоматически преобразовывает тип данных. Это надо учитывать, при работе с ассоциативными массивами. Так например, если в индекс передать число в виде строки (‘555’), то в индексе оно станет числом, или если в индекс передать true, то оно станет числом 1, а вот null превратиться в пустую строку. Пример кода см. ниже.
В массиве key может быть либо типа , либо типа . value может быть любого типа.
Дополнительно с ключом key будут сделаны следующие преобразования:
- Строки, содержащие целое число (исключая случаи, когда число предваряется знаком +) будут преобразованы к типу . Например, ключ со значением будет в действительности сохранен со значением 8. С другой стороны, значение не будет преобразовано, так как оно не является корректным десятичным целым.
- Числа с плавающей точкой (тип ) также будут преобразованы к типу , то есть дробная часть будет отброшена. Например, ключ со значением 8.7 будет в действительности сохранен со значением 8.
- Тип bool также преобразовываются к типу . Например, ключ со значением будет сохранен со значением 1 и ключ со значением будет сохранен со значением 0.
- Тип будет преобразован к пустой строке. Например, ключ со значением будет в действительности сохранен со значением .
Массивы (тип array) и объекты (тип object) не могут использоваться в качестве ключей. При подобном использовании будет генерироваться предупреждение: Недопустимый тип смещения (Illegal offset type). - Если несколько элементов в объявлении массива используют одинаковый ключ, то только последний будет использоваться, а все другие будут перезаписаны.
Вот пример:
$arr = [ '555' => 'val-1', // int(555) 555 .'' => 'val-2', // int(555) 'bar' => 'val-3', // "bar" false => 'val-4', // int(0) true => 'val-5', // int(1) null => 'val-6', // string(0) "" 0 => 'val-7', // int(0) 1 => 'val-8', // int(1) 8.7 => 'val-9', // int(8) '08' => 'val-10', // string(2) "08" 'val-11', // int(556) ]; var_dump( $arr ); /* array(8) { => string(5) "val-2" => string(5) "val-3" => string(5) "val-7" => string(5) "val-8" => string(5) "val-6" => string(5) "val-9" => string(6) "val-10" => string(6) "val-11" } */
Пример использования сессии
В данном примере я покажу как можно использовать сессии (сеансы) в PHP на практике. Для начала на сервере создадим файл со следующим содержимым:
<? // Создаётся пустой файл вида sess_819gk3tcdvilccra1t9kjdvsv9 // На машину пользователя прилетает сессионная кука с ID сессии. В данном случае 819gk3tcdvilccra1t9kjdvsv9 session_start(); // Инициализация строки с сообщениями об ошибках $message = ''; // Если запрос отправлен методом POST if ($_SERVER == "POST"): $name = strip_tags($_POST); $age = (int)$_POST; // Если поле `name` не заполнено if(empty($name)): $message = 'Поле `Ваше имя` обязательно к заполнению!'; // Иначе, если поле `age` не заполнено elseif(empty($age)): $message = 'Поле `Ваш возраст` обязательно к заполнению!'; // Если поля заполнены, записываем в сессию else: $_SESSION = $name; $_SESSION = $age; endif; // Иначе берём данные из сессии else: $name = $_SESSION ?? null; $age = $_SESSION ?? null; endif; ?> <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Сессии</title> </head> <body> <h1>Создание сессии</h1> <p><a href="destroy.php">Закрыть сессию</a></p> <p><?= $message ?></p> <form action="<?= $_SERVER ?>" method="post"> Ваше имя: <br> <input type="text" name="name" value="<?= $name ?>"><br><br> Ваш возраст: <br> <input type="text" name="age" value="<?= $age !== 0 ? $age : '' ?>"><br><br> <input type="submit" value="Отправить"> </form> <? if ($name and $age) { echo "<h3>Привет, $name!</h3>"; echo "<h3>Тебе $age лет</h3>"; } ?> </body> </html>
Здесь я постарался максимально понятно описать всё происходящее. Под пользователя при заходе на эту страницу уже создаётся сессия, она пустая, это пока просто файл. Если пользователь заполнил все необходимые поля формы и нажал кнопку `Отправить`, то созданный файл (файл сессии) заполниться данными. Далее скрипт проверяет, если есть в сессии данные именно этого пользователя (здесь он уже сравнивает с кукой, которая пришла до этого на машину пользователя), то выводим эти данные. В противном случае, добавляем в сессию данные пользователя.
Создадим файл . При переходе на данную страницу будем удалять сессию полностью. Если необходимо удалять и сессионную куку, воспользуйтесь функцией:
setcookie(session_name(), session_id(), time()-3600);
Что такое сессия в PHP?
Сессия — это механизм для сохранения информации на разных веб-страницах для идентификации пользователей пока они бродят по сайту или приложению. Вам интересно, почему сеансы нужны для веб-сайта? Чтобы понять, почему сеансы необходимы, нам нужно чуть вернуться назад и посмотреть, как работает HTTP-протокол.
Протокол HTTP — это протокол без учета состояния, что означает, что сервер не может сопоставить конкретного пользователя по несколькими запросами. Например, при доступе к веб-странице, сервер несёт ответственность за предоставление содержимого запрашиваемой страницы. Поэтому, когда вы обращаетесь к другим страницам одного и того же веб-сайта, веб-сервер интерпретирует каждый запрос отдельно, как если бы они не были связаны друг с другом. Серверу не известно, что каждый запрос исходит от одного и того же пользователя.
Следующая диаграмма вкратце изображает протокол HTTP.
В этой модели, если вы хотите отобразить пользовательскую информацию, вам нужно будет аутентифицировать пользователя в каждом запросе. Представьте, что вам нужно было вводить ваше имя пользователя и пароль на каждой странице с информацией ваших о данных! Да, это было бы громоздко и вообще не практично, и именно здесь на помощь приходят сеансы.
Сессия позволяет вам обмениваться информацией с разными страницами одного сайта или приложения, и помогает поддерживать состояние. Это позволяет серверу знать, что все запросы исходят от одного и того же пользователя, что позволяет сайту отображать информацию и настройки пользователя.
Давайте быстро рассмотрим общий пример входа на веб-сайт, чтобы понять, что происходит за кулисами.
- Пользователь открывает страницу входа на веб-сайт.
- После отправки формы входа, сервер, на другом конце, аутентифицирует запрос, проверив введённые учётные данные.
- Если учётные данные, введённые пользователем, верны, сервер создаёт новый сеанс. Сервер генерирует уникальное случайное число, которое называется идентификатором сеанса. Также, на сервере, создаётся новый файл, который используется для хранения информации, относящейся к сеансу.
- Затем, идентификатор сеанса передаётся обратно пользователю, вместе с тем, что он запросил. За кулисами этот идентификатор сеанса отправляется в заголовке ответа «куки» (так называется по умолчанию).
- Когда браузер получает ответ от сервера, он получает заголовок куки-файла . Если в браузере разрешены «куки», то он сохранит этот , в котором хранится идентификатор сеанса, переданный сервером.
- Для последующих запросов, «кука» передаётся обратно на сервер. Когда сервер получает «куку» , он пытается инициализировать сеанс с этим идентификатором сеанса. Он делает это, загружая файл сеанса, который был создан ранее во время инициализации сеанса. Затем он инициализирует суперглобальную переменную массива с данными, хранящимися в файле сеанса.
Таким образом, пользовательские данные сохраняются даже в нескольких запросах, и пользователь не теряется на протяжении всего сеанса.
На следующей диаграмме показано, как протокол HTTP работает с сеансами.
Теперь, когда вы увидели краткое введение в работу сессий, мы создадим несколько практических примеров, чтобы продемонстрировать, как создавать и манипулировать переменными сессии.
Увеличение строки ++
С числами все довольно просто, но что будет если инкрементить строки?
Что выведет данный код?
$a = 'fact_2'; echo ++$a; //> fact_3 $a = '2nd_fact'; echo ++$a; //> 2nd_facu $a = 'a_fact'; echo ++$a; //> a_facu $a = 'a_fact?'; echo ++$a; //> a_fact? $a = 'Привет'; echo ++$a; //> Привет
При инкременте строки, PHP увеличивает последний символ на символ следующий по алфавиту. И если в конце 2, то следующий символ будет 3. После t следует u. Однако эта операция не имеет никакого смысла в случае, когда строка заканчивается на не буквенно-численный символ.
Этот момент хорошо описан в официальной документации по операциям инкремента/декремента, однако многие не читали этот материал, потому что не ожидали встретить там ничего особенного.
Introduction
PHP is a web-focussed programming language, so processing user data is a frequent activity. In such processing it is common to check for something’s existence, and if it doesn’t exist, use a default value. Yet the simplest way to do this, something along the lines of , is unnecessarily cumbersome. The short ternary operator, provides a way to do this much more conveniently: . However, this is not good practice, as if the value does not exist it will raise an . Because of these issues, some sort of ifsetor() operator or a modification to ‘s behaviour to make this common pattern easier has been a frequent request (See References).
Все объекты в PHP передаются по ссылке
Это свойство объектов вам возможно известно, но даже в этом случае можно поймать баг, поэтому при работе с объектами будьте внимательны.
Для примера, давайте рассмотрим такой код, когда мы используем объект для удобства, который создается из массива:
$data = (object) array( 'my_val' => 'bar', ); $var = $data; $var->my_val = 'new_bar'; $var2 = $data; echo $var2->my_val; //> new_bar
Мы создали казалось бы общие данные, который потом планируем использовать в разных переменных, меняя данные объекта где нужно, а где не нужно оставляя исходный вариант. В этом случае изменение данных будет менять их и в исходном варианте…
Так, например, если использовать массив, то все будет работать как мы ожидаем. Тот же код но с массивом:
$data = array( 'my_val' => 'bar', ); $var = $data; $var = 'new_bar'; $var2 = $data; echo $var2; //> bar
Поэтому чтобы первый вариант работал правильно, в переменную нужно передавать копию объекта, создаваемую с помощью clone:
$data = (object) array( 'foo' => 'bar', ); $var = clone $data; $var->foo = 'new_bar'; $var2 = clone $data; echo $var2->foo; //> bar
Ключевое слово revert#
Но что, если мы хотим сбросить значение свойства до первоначально заданных браузером значений, а не до значений по умолчанию? Например, вернуть значение свойства элемента к значению (это стили браузера), а не к значению (это базовые стили CSS).
Браузерные стили для тега div
Для этих целей мы скоро получим новое ключевое слово в CSS: . Оно очень похоже на , единственное отличие состоит в том, что оно предпочитает стили браузера базовым значениям свойств CSS. Например:
Таким образом, если мы хотим сбросить все стили HTML-элемента до базовых стилей браузера, мы можем сделать это так:
Соответственно, дает гораздо больше возможностей, чем . Правда, на данный момент работает только в Firefox и Safari. (В Chrome работает с версии 84 — прим. переводчика.)
Удаляем повторяющиеся элементы массива в PHP
Порой возникает необходимость удалить повторяющиеся элементы массива в PHP. Для решения этой задачи существует специальная функция под названием array_unique():
<?php $stack = array('a', 'b', 'b', 'c', 'c', , '0'); $stack = array_unique($stack); print_r($stack); //на экране отобразится: Array ( => a => b => c => 0 ) ?>
Из кода видно, что функция удалила из PHP-массива повторяющиеся элементы. При этом функция имеет ещё один параметр, указывающий, как сравнивать элементы.
Возможные типы сравнения:
• SORT_REGULAR — сравнение без преобразования типа элементов;
• SORT_STRING — сравнение как строки;
• SORT_NUMERIC — сравнение как чисел (пытаемся преобразовать в число);
• SORT_LOCALE_STRING — сравнение как строки, но с учётом выбранного набора символов.
По умолчанию применяется SORT_STRING
Выбирая типы сравнения, помните, что это важно. Давайте изменим тип в прошлом примере на SORT_NUMERIC:
<?php $stack = array('a', 'b', 'b', 'c', 'c', , '0'); $stack = array_unique($stack, SORT_NUMERIC); print_r($stack); //на экране отобразится: Array ( => a ) ?>
Во время сравнения все элементы массива были преобразованы к численному типу скаляра. В нашем случае это неизменно давало значение ноль, в результате чего у нас остался лишь первый элемент.
Хотите знать о PHP больше? Записывайтесь на курс «Backend-разработчик на PHP»!
Closure::call — вызов анонимной функции с указанием контекста
Это не столько неожиданность, сколько интересная особенность, о которой мало кто знает.
PHP замыкания (анонимные функции) можно вызывать передавая в них контекст (объект). В результате замыкание можно использовать как метод переданного объекта.
Для этого в объекте замыкания есть метод:
call( $that, ...$params )
- $that(object)
- Объект для привязки к замыканию на время его вызова.
- …$params
- Сколько угодно параметров, которые передаются в замыкание.
Пример того как это использовать
class Value { protected $value; function __construct( $value ){ $this->value = $value; } function get_value(){ return $this->value; } } $three = new Value( 3 ); $four = new Value( 4 ); $closure = function( $delta ){ echo $this->get_value() + $delta; }; $closure->call( $three, 4 ); // 7 $closure->call( $four, 4 ); // 8
Что мы видим? При вызове одного и того же замыкания мы получаем разный результат, который зависит от контекста вызова (от того какой объект передается и используется в замыкании).
Null Оператор ??
В отличие от некоторых языков, где вы можете использовать имя переменной в качестве выражения в выражении и смело предполагать, что если значение не определено или пустое, то значение будет , PHP же будет бросать ошибку о неопределенной переменной, индексе и т. д. Это делает очень многословным, обычный код, с использованием , чем другие языки, как например, в следующем примере.
Даже при использовании тернарного оператора необходима функция . С новым null оператором вы можете существенно облегчить код:
Такое использование еще более эффективно в случаях цепочной проверки, требующих одного или несколько других операторов .
Маленькое дополнение: Если вы работаете с JavaScript, вы можете делать такие вещи:
Это не будет работать в PHP, и эквивалентный код на PHP установит значение 0, поскольку новый оператор работает только с значениями.
Странное поведение в PHP при передаче значения foreach по ссылке
$array = ; foreach( $array as & $item ){ } foreach( $array as $item ){ } print_r( $array ); /* Array ( => a => b => b ) */
Мы дважды проводим итерацию по массиву, ничего не делая. Так что в результате никаких изменений не должно быть. Правильно? — Неправильно!
Что же произошло? Собственно, ничего такого, чтобы мы сами не просили сделать PHP. В первом цикле мы объявили ссылку & $item, которая после завершения работы цикла указывает на элемент массива $list. Далее мы пробегаемся ещё раз по массиву, на каждом шаге присваивая переменной $item очередное значение. Т.к. в PHP область видимости переменных не ограничивается блоком составного оператора, то переменная $item во втором цикле — это та же самая переменная из первого цикла. Поэтому, одновременно с установкой значения переменной $item, это же значение присваивается и элементу $list.
- Шаг 0: $item = $list = $list = 2
- Шаг 1: $item = $list = $list = 3
- Шаг 2: $item = $list = $list = 3
foreach( $a as & $v ){} unset($v);
Как удалить пустые элементы из массива?
Сначала вспомним, что называют пустым элементом. Лучше всего определить «пустое значение» помогает результат работы функции empty(). Функция возвратит true для пустого элемента, причем не только скалярного. Убедимся в этом на примере ниже:
<?php $stack = array(3 => 'a', 5 => 'b', '3rd' => 'c', array(), null, false, , '', '0', '00'); foreach ($stack as $k => $v) if (empty($v)) unset($stack$k]); print_r($stack); //на экране отобразится : Array ( => a => b => c => 00 ) ?>
Итак, мы в цикле проверим каждый элемент массива, используя функцию empty() и удалим пустые элементы
Здесь важно понять, что строковый скаляр ‘0’ — тоже пустой элемент. А вот ’00’ пустым не является
Если считаете, что поэлементная проверка массива — неоптимальный вариант, воспользуйтесь функцией сравнения массивов в PHP — array_diff(), перечислив с её помощью все элементы, которые считаем «нулевыми»:
<?php $stack = array(3 => 'a', 5 => 'b', '3rd' => 'c', array(), null, false, , '', '0', '00', ' '); $stack = array_diff($stack, array(array(), null, false, , '', '0', '00', ' ')); print_r($stack); //на экране отобразится: Array ( => a => b => c ) ?>
Очевидно, что данный способ более гибок.
Точное сравнение
PHP язык без строгой типизации и потому иногда могут возникать неожиданные результаты при сравнении (проверке) разных значений…
if( 0 == 'строка' ) echo 'Неужели?'; // Условие сработает и мы увидим: 'Неужели?' // другими словами - строка превращается в число при сравнении и становится 0: var_dump( 0 == 'строка' ); //> bool(true) // но var_dump( '0' == 'строка' ); //> bool(false)
Происходит так очевидно, потому что превращается в ноль: , а это true, разумеется…
Так например можно пропустить переменную запроса:
// $_GET может быть любой строкой и проверка всегда будет срабатывать... if( $_GET == 0 ){ echo $_GET; } // поэтому по возможности ставьте проверку строго по типу if( $_GET === '0' ){ echo $_GET; }
Все следующие значения одинаковы, при сравнении через (не строгий оператор сравнения):
0 == false == "" == "0" == null == array()
Ну и так:
1 == '1нечто' == true true == array(111)
empty() и объекты
Проверка empty() на объектах может вести себя странно. Допустим у нас есть некий объект и мы проверяем пусто ли свойство , и получаем такое:
if( empty( $obj->var ) ){ // условие сработает } if( ! $obj->var ){ // условие не сработает }
Парадокс! Как такое может быть? empty() говорит что свойство пустое, а говорит что в нем что-то есть. Как одно и тоже свойство может быть пустым и не пустым одновременно? Квантовая суперпозиция господа…
Однако если разобраться, то нет тут ничего удивительного и все логично!
Дело в том, что конструкция empty() обращается к встроенному методу объекта __isset(), а прямой запрос свойства ($obj->var) обратиться к __get().
Т.е. получается empty() и ! запрашивают разные методы, если свойство не установлено:
class FOO { function __get( $name ){ if( $name == 'bar' ) return true; } } $obj = new FOO; var_dump( empty($obj->bar) ); //> bool(true) - переменной нет var_dump( ! $obj->bar ); //> bool(false) - переменная есть
А теперь, зададим значение свойства bar в __isset() и empty() его получит:
class FOO { function __isset( $name ){ if( $name == 'bar' ) return true; } function __get( $name ){ if( $name == 'bar' ) return true; } } $obj = new FOO; var_dump( empty($obj->bar) ); //> bool(false) - переменная есть var_dump( ! $obj->bar ); //> bool(false) - переменная есть
Ключевое слово initial#
Чтобы понять ключевое слово , мы должны помнить важный факт: у каждого свойства в CSS есть значение по умолчанию, которое не имеет ничего общего со значениями, которые устанавливаются браузером. Браузерные стили — это стили, которые применяются браузером к конкретным HTML-элементам. Мы часто думаем, что они автоматически приходят вместе с HTML, но это не так.
Ключевое слово говорит браузеру использовать значение по умолчанию для заданного CSS-свойства. Например, для свойства значение всегда будет .
Такое поведение может очень запутывать, потому что, как мы и говорили ранее, значение по умолчанию для CSS-свойства не всегда совпадает со значением, которое браузер задает конкретному элементу. Например, -значение для свойства равно для всех элементов. Поэтому, если для элемента будет задано свойство со значением , то свойство будет вычислено как , а не , как в стилях браузера.
Пример:
Информация об -значении свойства на MDN.
Что же в Java Enterprise?
К великому счастью, разработчики JavaEE освобождены от такой рутины и выполнение данной задачи взвалено на плечи контейнера, в пределах которого развёрнуто приложение. Осталось понять, каким же образом он это делает?
Работа с пользовательскими сессиями веб-приложений в JavaEE вынесена в раздел Servlet API и осуществляется средствами интерфейса javax.servlet.http.HttpSession, который предоставляет высокоуровневые методы работы с ними. Непосредственная реализация уже располагается в библиотеке servlet-api.jar используемого контейнера сервлетов и напрямую зависит от него. Существует два способа получения ссылки на объект пользовательского сеанса из объекта клиентского запроса javax.servlet.http.HttpServletRequest, используя методы Servlet API:
- HttpSession request.getSession(boolean create) — для ложного значения параметра create данный метод возвращает объект сессии, если он был создан у данного запроса, и null в противном случае; в случае истинного значения create данный метод равносилен методу п.2.
- HttpSession request.getSession() — если сеанс не установлен, то контейнер его создаёт, иначе возвращает уже созданный объект сессии.
В момент, когда сеанс установлен, сервлет-контейнер создаёт пользовательский cookie с именем JSESSIONID, значение которого содержит уникальный идентификатор сессии (это же значение можно получить методом String getId() объекта HttpSession). Наряду с этим, в рамках контейнера определяется дефолтное значение таймаута сессии — время неактивного состояния пользователя, приводящее к устареванию его сеанса связи с сервером.
Данное значение конфигурируется на уровне контейнера сервлетов либо непосредственно в веб-приложении на уровне дескриптора развёртывания web.xml или непосредственным вызовом метода void setMaxInactiveInterval(int interval) у объекта сессии. Начиная с версии Servlet API 3.0, также можно задать и время жизни куки JSESSIONID в конфиге web.xml, уничтожение которой также приведёт к запросу на повторное установление сеанса между клиентом и сервером. Кусок дескриптора развертывания web.xml:
<session-config> <!-- Timeout of inactivity in minutes --> <session-timeout>15</session-timeout> <cookie-config> <http-only>true</http-only> <path>/</path> <!-- Cookie lifetime in seconds --> <max-age>900</max-age> </cookie-config> </session-config>
А что же будет, если пользовательские «печеньки» запрещены на клиентской машине? Данный факт будет выявлен сервером автоматически и для поддержания сеанса будет использован механизм URL Rewriting, который позволяет передавать UID-сессии непосредственно в адресной строке, например так:
http://www.mysite.com/MyApp/myservlet;jsessionid=1E6FEC0D14D044541DD84D2D013D29ED
А зачем они вообще нужны эти http-сессии и какие в принципе возможности они предоставляют — это уже отдельная тема.
Разница между PHP операторами OR и ||, AND и &&
PHP операторы OR, AND и ||, && соответственно, отличаются приоритетами выполнения. У последних он выше, поэтому они будут выполняться раньше.
Если сравнивать с оператором присваивания: , то OR/AND будут выполняться ПОСЛЕ оператора присваивания, в то время как у || и && будут выполняться ДО оператора присваивания, из за более высокого приоритета. Рассмотрим эту разницу на примере:
OR и ||
$true = true; // присваиваем $false = false; // присваиваем $var = $false OR $true; // результат: $var = false // потому что присваивание сработает раньше чем сравнение OR // действует как: ( ($var = $false) or $true ) $var2 = $false || $true; // результат: $var2 = true // так как первым произошло сравнение, а уже потом присваивание var_dump( $var, $var2 ); // bool(false), bool(true)
AND и &&
// "&&" имеет больший приоритет, чем "and" $var = true && false; // результат выражения (true && false) присваивается переменной $g // работает как: ($var = (true && false)) $var2 = true and false; // константа true присваивается $var2, а затем значение false игнорируется // работает как: (($var2 = true) and false) var_dump( $var, $var2 ); //> bool(false), bool(true)
Proposal
The coalesce, or , operator is added, which returns the result of its first operand if it exists and is not NULL, or else its second operand. This means the is completely safe and will not raise an E_NOTICE. Some examples of its use:
// Fetches the request parameter user and results in 'nobody' if it doesn't exist $username = $_GET'user' ?? 'nobody'; // equivalent to: $username = isset($_GET) ? $_GET : 'nobody'; // Calls a hypothetical model-getting function, and uses the provided default if it fails $model = Model::get($id) ?? $default_model; // equivalent to: if (($model = Model::get($id)) === NULL) { $model = $default_model; } // Parse JSON image metadata, and if the width is missing, assume 100 $imageData = json_decode(file_get_contents('php://input')); $width = $imageData'width' ?? 100; // equivalent to: $width = isset($imageData) ? $imageData : 100;
It can even be chained:
$x = NULL; $y = NULL; $z = 3; var_dump($x ?? $y ?? $z); // int(3) $x = "yarr" => "meaningful_value"; var_dump($x"aharr" ?? $x"waharr" ?? $x"yarr"); // string(16) "meaningful_value"
This example demonstrates the precedence relative to the ternary operator and the boolean or operator, which is the same as C#:
var_dump(2 ?? 3 ? 4 5); // (2 ?? 3) ? 4 : 5 => int(4) var_dump( || 2 ?? 3 ? 4 5); // ((0 || 2) ?? 3) ? 4 : 5 => int(4)
This example demonstrates how it is a short-circuiting operator:
function foo() { echo "executed!", PHP_EOL; } var_dump(true ?? foo()); // outputs bool(true), "executed!" does not appear as it short-circuited
В чем отличие между функциями isset(), empty() и is_null() в PHP?
Из приведенных выше определений видно, что эти три функции выполняют сходные, но не одинаковые функции. С помощью этих функций вы можете проверять, является ли переменная нулевой (NULL), истинной (TRUE) или ложной (FALSE), а также была ли переменная объявлена.
Когда использовать функцию empty()?
При использовании , вы можете проверять, является ли переменная ложной (false), но также и то, существует ли переменная. Эту функцию лучше всего использовать, когда вы хотите убедиться, что переменная существует и имеет значение, которое не равно
Обратите внимание, что PHP будет обрабатывать пустые строки, целые числа 0, числа с плавающей запятой 0.0, пустые массивы и логическое значение как false. Таким образом, в основном, используйте только тогда, когда вы хотите убедиться, что в переменной есть какое-то фактическое значение
Поскольку вам не нужно объявлять переменные перед их использованием в PHP, вы можете оказаться в ситуации, когда вы пытаетесь выполнить действия или запустить другую проверку для переменной, которая еще не была объявлена. Хотя по этой и другим причинам рекомендуется объявлять переменные перед использованием, эта ошибка – одна из причин того, что используется не так, как .
Когда использовать функцию isset()?
Если вы используете , вы можете специально проверять, была ли переменная уже объявлена и что ее значение не равно . Таким образом, пока у вас есть объявленная переменная, у которой установлено значение, но не значение , при тесте вы получите . Это хорошее условие для проверки, перед выполнением других проверок для выполнения действий с переменной. Пример:
<?php $variable = 'Какая-то строка'; // Объявление переменной // Проверка существования переменной, затем проверка значения if ( isset($variable) && $variable !== 'Какая-то другая строка' ) { echo 'Этот код сработает, поскольку оба условия верны'; } ?>
В приведенном выше примере мы объявили нашу переменную в виде строки, а затем проверили, установлена ли переменная (установлена), и она не равна другой строке (она не равна). Поскольку оба этих условия верны, мы в этом условии можем проводить дальнейшие действия с переменной и ее значением.
Когда использовать функцию is_null()?
Наконец, функция работает аналогично функции , с одним ключевым отличием: переменная должна быть объявлена, чтобы вернулся , даже при условии, что она объявлена без какого-либо значения или определена как .
В противном случае функция не только не будет правильно работать, но и будет возвращать уведомление из-за невозможности провести проверку. Обычно уведомление выглядит примерно так:
Notice: Undefined variable: variable in /{PATH}/ on line X
Поскольку является языковой конструкцией и может обрабатывать переменные, которые не были объявлены, обычно рекомендуется использовать в большинстве случаев. Если вам нужно использовать , вам нужно найти другой способ функционирования вашего кода.
Какой ответ возвращают функции isset(), empty() и is_null() в PHP
В приведенной ниже таблице рассмотрены основные результаты использования данных функций в PHP коде:
Значение переменной ($var) | |||
---|---|---|---|
«» (пустая строка) | bool(true) | bool(true) | bool(false) |
» » (пробел) | bool(true) | bool(false) | bool(false) |
FALSE | bool(true) | bool(true) | bool(false) |
TRUE | bool(true) | bool(false) | bool(false) |
array() (пустой массив) | bool(true) | bool(true) | bool(false) |
NULL | bool(false) | bool(true) | bool(true) |
«0» (0 в виде строки) | bool(true) | bool(true) | bool(false) |
0 (0 в виде целого числа) | bool(true) | bool(true) | bool(false) |
0.0 (0 в виде числа с плавающей точкой) | bool(true) | bool(true) | bool(false) |
переменная $var; (переменная объявлена, но без значения) | bool(false) | bool(true) | bool(true) |
На сегодня все. Спасибо, что читаете нас!
in_array() нас обманывает
Вы мастер массивов в PHP. Вы уже знаете все о создании, редактировании и удалении массивов. Тем не менее, следующий пример может вас удивить.
Часто при работаете с массивами приходится в них что-либо искать с помощью in_array().
$array = array( false, true, 1 ); if( in_array( 'строка', $array ) ){ echo 'Неужто нашлось'; }
Как думаете выведет этот пример надпись «Неужто нашлось»? После такого вопроса, вы наверняка решили что условие сработает, но при написании кода, скорее всего было бы наоборот — и вы бы решили что условие не сработает На самом деле, это условие сработает и код выведет надпись «Неужто нашлось».
Так происходит, потому что PHP язык бестиповой и in_array() в данном случае сравнивает значения, но не учитывает тип, т.е. использует оператор ==, а не ===. А даст нам true. Вот и получается что in_array() лжёт!
Решение
Чтобы избежать такого «обмана», нужно указать true в третий параметр в in_array(), так все сравнения будут проходить с учетом типа значения.
$array = array( false, true, 1 ); if( in_array( 'строка', $array, true ) ) echo 'Неужто нашлось'; else echo 'Не найдено'; // сработает этот вариант условия
Обзор функций isset(), empty() и is_null() в PHP
Все эти три функции встроены в PHP, поэтому при написании кода они всегда доступны для использования. Первые две – и – это языковые конструкции, а – это стандартная функция. При проверке кода необходимо помнить, что языковые конструкции в PHP немного быстрее (но, честно говоря, не значительно), их нельзя использовать в переменных функциях, и они не выдают ошибки при оценке переменных, которых не существует.
Давайте для начала рассмотрим синтаксис и краткое описание этих трех функций, которое указано в официальном руководстве php.net.
Функция empty()
Синтаксис функции:
<?php empty ( mixed $var ) : bool ?>
Определяет, является ли переменная пустой. Переменная считается пустой, если она не существует или если ее значение равно . При этом, если переменная не существует, функция не выдает предупреждения.
Функция isset()
Синтаксис функции:
<?php isset ( mixed $var ) : bool ?>
Определяет, установлена ли переменная, и не имеет ли она значение .
Если переменная была сброшена (удалена) с помощью функции , такая переменная больше не будет установлена. Функция при тестировании (проверке) переменной вернет , если для нее установлено значение
Также обратите внимание, что нулевой символ (««) не эквивалентен PHP константе
Если задано несколько параметров, тогда вернет , но только если все параметры определены. Оценка идет слева направо и останавливается, как только встречается неустановленная переменная.
Функция is_null()
Синтаксис функции:
<?php is_null ( mixed $var ) : bool ?>
Определяет, является ли данной переменной значение, равное .