git / code.ach.gov.ru / kabakov_iv / bitrix_php_code_standarts

commit 22653eff70c79991595d247e629bb09183c574f9

author kabakov_iv <kabakov.i@yandex.ru>

date 2026-05-06 14:10:06 +0300

parents 3db856f3

browse tree at this commit

message

добавлена статья isset-vs-empty

files

fileadddel
src/tips/index.md+25-0
src/tips/isset-vs-empty.md+262-0

patch

diff --git a/src/tips/index.md b/src/tips/index.md
new file mode 100755
index 0000000000000000000000000000000000000000..43b38573c02c871fa3f4b12f0ecc5fb93a1f6499
--- /dev/null
+++ b/src/tips/index.md
@@ -0,0 +1,25 @@
+# Tips — Тематические статьи
+
+[← Оглавление](../index.md)
+
+---
+
+Этот раздел содержит глубокие разборы конкретных конструкций, операторов и паттернов PHP и Bitrix24. В отличие от основных разделов руководства, каждая статья посвящена одной узкой теме и рассматривает её исчерпывающе: поведение во всех граничных случаях, таблицы сравнения, практические примеры.
+
+Статьи дополняют основное руководство — в основных разделах на них даются ссылки там, где тема требует более подробного объяснения.
+
+---
+
+## Список статей
+
+| Статья | Описание | Связанные разделы |
+|--------|----------|-------------------|
+| [isset() vs empty()](./isset-vs-empty.md) | Детальный разбор поведения, таблица всех значений, подводные камни строки `"0"`, оператор `??` | [04 — Контроллеры](../04-controllers.md), [09 — Безопасность](../09-security.md) |
+
+---
+
+## Как добавить новую статью
+
+1. Создайте файл `src/tips/название-темы.md`
+2. Добавьте строку в таблицу выше
+3. При необходимости добавьте ссылку из соответствующего раздела руководства
diff --git a/src/tips/isset-vs-empty.md b/src/tips/isset-vs-empty.md
new file mode 100755
index 0000000000000000000000000000000000000000..c69a22d408004034ba3665de1ffd86a09d81c7cc
--- /dev/null
+++ b/src/tips/isset-vs-empty.md
@@ -0,0 +1,262 @@
+# `isset()` vs `empty()` в PHP: полный разбор
+
+[← Tips](./index.md) · [← Оглавление](../index.md)
+
+---
+
+## Суть различия в одном предложении
+
+- **`isset()`** проверяет, **существует ли переменная** и не равна ли она `null`.
+- **`empty()`** проверяет, является ли переменная **«пустой»** в понимании PHP. Если переменной не существует — `empty()` просто считает её пустой и не генерирует предупреждение.
+
+---
+
+## Детальный разбор `isset()`
+
+`isset()` возвращает `true`, только если переменная **определена** и её значение **не равно `null`**. Во всех остальных случаях — `false`.
+
+**Вернёт `true`:**
+- Переменная объявлена и равна чему угодно, кроме `null` — пустая строка `''`, `0`, `false`, пустой массив `[]` — всё это `true` для `isset()`.
+
+**Вернёт `false`:**
+- Переменная не объявлена.
+- Переменной присвоено значение `null`.
+- Переменная была удалена через `unset()`.
+
+---
+
+## Детальный разбор `empty()`
+
+`empty()` возвращает `true`, если переменная **не существует** или её значение **приводится к логическому `false`**.
+
+**`empty()` вернёт `true` для следующих значений:**
+
+| # | Значение | Тип |
+|---|----------|-----|
+| 1 | `""` | пустая строка |
+| 2 | `"0"` | строка с нулём — **частый источник ошибок!** |
+| 3 | `0` | целое число |
+| 4 | `0.0` | число с плавающей точкой |
+| 5 | `false` | булево |
+| 6 | `null` | null |
+| 7 | `[]` | пустой массив |
+| 8 | переменная не объявлена | — |
+
+Все остальные значения (`true`, непустые строки, непустые массивы, отрицательные числа, строка `"false"` и т.д.) дадут `false`.
+
+---
+
+## Таблица сравнения
+
+| Значение переменной `$var` | `isset($var)` | `empty($var)` | Комментарий |
+|:---|:---:|:---:|:---|
+| Переменная не объявлена | `false` | `true` | `empty()` не генерирует Warning — в отличие от прямого `if ($var)` |
+| `$var = null;` | `false` | `true` | Для `isset()` — как будто переменной нет |
+| `$var = true;` | `true` | `false` | |
+| `$var = false;` | `true` | `true` | `false` считается пустым значением |
+| `$var = 0;` | `true` | `true` | `0` считается пустым значением |
+| `$var = 0.0;` | `true` | `true` | `0.0` считается пустым значением |
+| `$var = "0";` | `true` | `true` | ⚠️ Строка `"0"` считается пустой |
+| `$var = "";` | `true` | `true` | |
+| `$var = " ";` | `true` | **`false`** | Пробел — не пустое значение для `empty()` |
+| `$var = "false";` | `true` | **`false`** | ⚠️ Строка `"false"` — непустая, `empty()` вернёт `false` |
+| `$var = [];` | `true` | `true` | |
+| `$var = [0];` | `true` | `false` | Массив с одним элементом не пуст, даже если элемент `0` |
+| `$var = new stdClass();` | `true` | `false` | Объект без свойств не считается пустым (PHP 5.5+) |
+
+---
+
+## Ключевые нюансы и подводные камни
+
+### 1. Безопасность при обращении к несуществующей переменной
+
+Обе конструкции не генерируют Warning при обращении к необъявленной переменной или несуществующему индексу массива — в отличие от прямого `if ($var)`.
+
+```php
+// Безопасно, Warning не будет, вернёт true
+if (empty($nonExistentVariable)) {
+    echo 'Переменной нет или она пуста';
+}
+
+// Безопасно, Warning не будет, вернёт false
+if (isset($nonExistentVariable)) {
+    // Сюда не попадём
+}
+```
+
+---
+
+### 2. ⚠️ Проблема строки `"0"`
+
+Самый известный подводный камень `empty()`. Строка `"0"` считается пустой. Если строка `"0"` — валидное значение (например, количество товара), использование `empty()` приведёт к логической ошибке.
+
+```php
+$userInput = '0';
+
+// empty() посчитает, что пользователь ничего не ввёл — это ошибка логики
+if (empty($userInput)) {
+    echo 'Вы ничего не ввели'; // ← выполнится, хотя "0" было введено
+}
+
+// Корректная проверка, когда "0" — валидное значение
+if ($userInput !== '') {
+    echo 'Спасибо за ввод!'; // ← правильное поведение
+}
+```
+
+---
+
+### 3. `isset()` проверяет несколько переменных сразу
+
+`isset()` принимает несколько аргументов и вернёт `true` только если **все** переменные определены и не `null`. У `empty()` такой возможности нет.
+
+```php
+$a = 1;
+$b = null;
+$c = 3;
+
+var_dump(isset($a, $b, $c)); // false — $b === null
+
+// Для empty нет аналогичного синтаксиса,
+// пришлось бы писать: empty($a) || empty($b) || empty($c)
+// — но это уже другая логика (ИЛИ вместо И)
+```
+
+---
+
+### 4. `empty()` принимает выражения (начиная с PHP 5.5)
+
+Начиная с **PHP 5.5** в `empty()` можно передавать не только переменные, но и произвольные выражения, включая вызовы функций:
+
+```php
+// Работает начиная с PHP 5.5 — никакой ошибки нет
+if (empty(trim($name))) {
+    echo 'Имя не указано';
+}
+```
+
+> До PHP 5.5 это действительно вызывало Fatal error — но все актуальные версии (7.x, 8.x) поддерживают такой синтаксис без ограничений.
+
+---
+
+### 5. `isset()` и магический метод `__isset()` на объектах
+
+При вызове `isset($object->property)` на недоступном (private/protected) или несуществующем свойстве PHP вызывает магический метод `__isset()`. Это важно при работе с ORM, ActiveRecord и Bitrix-сущностями:
+
+```php
+class Foo {
+    public function __isset(string $name): bool {
+        return $name === 'bar'; // управляем поведением вручную
+    }
+}
+
+$foo = new Foo();
+var_dump(isset($foo->bar)); // true  — отработал __isset()
+var_dump(isset($foo->baz)); // false — __isset() вернул false
+```
+
+Если класс не реализует `__isset()`, обращение к недоступному свойству через `isset()` просто вернёт `false` без ошибок.
+
+---
+
+### 6. Внутренняя логика `empty()`
+
+По сути, `empty($var)` — это полный безопасный эквивалент `!isset($var) || $var == false`. Обратите внимание: используется **нестрогое сравнение `==`**. Именно поэтому `"0"`, `0`, `0.0`, `""` и `[]` приравниваются к `false`.
+
+---
+
+## Примеры из практики: когда что использовать
+
+### Сценарий 1: Проверка обязательного поля формы
+
+Нужно убедиться, что поле существует и не пустое. При этом `"0"` — валидное значение (например, количество товара).
+
+```php
+// ❌ Плохо — строка "0" не пройдёт проверку
+if (!empty($_POST['quantity'])) {
+    $quantity = $_POST['quantity'];
+}
+
+// ✅ Хорошо — явная проверка на непустую строку + trim на случай пробелов
+if (isset($_POST['quantity']) && trim($_POST['quantity']) !== '') {
+    $quantity = $_POST['quantity'];
+}
+```
+
+---
+
+### Сценарий 2: Проверка чекбокса
+
+Если HTML-чекбокс не отмечен, ключ в `$_POST` просто отсутствует. Нас интересует факт наличия, а не значение.
+
+```php
+// ✅ Идеально подходит isset() — точно выражает намерение
+if (isset($_POST['agree_to_terms'])) {
+    // Пользователь согласился с условиями
+}
+```
+
+---
+
+### Сценарий 3: Значение по умолчанию из конфига
+
+```php
+// PHP 7.0+ — оператор ?? (null coalescing)
+// Вернёт $config['max_items'], если ключ существует и не null, иначе 10
+$limit = $config['max_items'] ?? 10;
+
+// PHP 7.4+ — оператор ??= (присваивает, только если null или не существует)
+$config['max_items'] ??= 10;
+```
+
+Оператор `??` — это прямой синтаксический сахар для `isset()`. Предпочитайте его вместо тернарного оператора с `isset()`.
+
+---
+
+### Сценарий 4: Проверка пустого массива
+
+```php
+$items = [];
+
+// ✅ empty() читается естественно — «если массив пуст»
+if (empty($items)) {
+    echo 'Нет элементов.';
+}
+
+// Многословный аналог — избыточно
+// if (isset($items) && count($items) === 0) { ... }
+```
+
+---
+
+## Итоговый алгоритм выбора
+
+```
+Нужно проверить существование переменной / ключа массива
+и исключить null?
+    → isset()  или оператор ??
+    
+Нужно проверить «пустоту» переменной (0, "", [], false — всё пустое),
+и строка "0" НЕ является валидным значением?
+    → empty()
+    
+Нужно проверить непустую строку, где "0" — валидное значение?
+    → isset($var) && trim($var) !== ''
+    (забудьте про empty() в этом случае)
+    
+Нужно присвоить значение по умолчанию, если переменной нет или она null?
+    → $value = $var ?? 'default';
+    или $var ??= 'default';  (PHP 7.4+)
+```
+
+---
+
+## Краткая шпаргалка
+
+```php
+isset($var)          // существует И не null?
+isset($a, $b, $c)    // все существуют И не null?
+empty($var)          // не существует ИЛИ == false (включая "0", 0, [], "")?
+$var ?? 'default'    // $var если isset(), иначе 'default'
+$var ??= 'default'   // присвоить 'default' если !isset() или null (PHP 7.4+)
+```