Pull to refresh

Comments 55

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

необходима функция isset

Всегда предпочитал !empty().
Я в курсе. К чему эта портянка? Вы не поняли, где у вас в тексте ошибка?

смело предполагать, что если значение… пустое, то значение будет false
функция isset

isset() на пустую строку, false, число 0, строку '0' даст true.
Эта функция не для проверки значения, она для проверки факта существования переменной.
Тщательне́е надо.
Все он правильно сказал, все что вы перечислили не пустые значения
Собственно, NULL — это даже не пустое значение, это отсутствие значения вообще. Даже пустого.
Ой не пойму я, чего вы спорите, берем и пишем:
$arr = ['', 0, '0', false, NULL];
echo "Num\tEmp\tSet\tNul\tBool\n";
for($i = 0; $i < 5; $i++) {
    echo $i, "\t", empty($arr[$i]), "\t", isset($arr[$i]), "\t", is_null($arr[$i]), "\t", boolval($arr[$i]), "\n";
}

смотрим на вывод и делаем выводы.

ЗЫ. Если лень заморачиваться: с одной стороны, NULL означает отсутствие значения, с другой, мы можем написать $a=NULL. Это значит, что значение может быть установлено, но оно все равно будет неопределено. Даже более простой случай со строкой '0' заставляет нас помнить о контексте использования: если работаем со строкой, то это эквивалентное true значение, а если с числами, то false. В общем, нельзя расслабляться, даже в мелочах.
Всегда предпочитал !empty().

Не подходит, когда значение может быть 0, false и т д
Да, но подходит для того что описал автор:
значение не определено или пустое
что собственно и процитировал 027 в своём первом комментарии.
Причём под этой фразой автор проверяет только на «определено» isset(), но не проверяет на «пустое» (перевод — правильный, в оригинале — «the value isn’t defined or is empty», значит ошибку допустил автор в коде или его описании), нужно isset($x) && $x, на что 027 и ответил, что в таких случаях предпочитает использовать !empty(), что вполне логично, так многие и делают.
@27 вырвал фразы из разных контекстов, автор пишет:

Даже при использовании тернарного оператора необходима функция isset


т е имеется ввиду что-то вроде такого:

$value = isset($_GET['limit']) ? $_GET['limit'] : 10;


конечно щависит от ситуации, иногда тебе подойдет и empty, но однозначто это сказать нельзя, поэтому они и неэквивалентны
А что значит пустое? 0 пустое значение? А если мне надо число в промежутке от -1 до 1, значит ли это что валидных значения всего два? Ведь ноль пустое значение. Да и фолс, мне нужен ответ человека на вопрос: «курит ли он», бессмысленно хранить его как текст да/нет, бул предпочтительней. К пустому значению с натяжкой можно лишь пустую строку притащить, ито даже это значение может быть вполне себе валидным и полным значением отвечающим требованию.
Сама фраза пустое значение изначально неправильная. Эти значения не пустые, они вполне себе определенные и ими можно оперировать. Только по этому к нему придираются, а не из-за неправильного перевода или чего бы то еще.
В php всё просто — пустое значение или нет определяется с помощью функции empty().
Не подходит для чего именно?

isset() даст true, если переменная существует и ей не присвоено NULL.
!empty() даст true, если переменная существует, и заодно не NULL, не нуль (целое либо дробное), не символ нуль (string '0'), не пустая строка, не пустой массив, не false.

То есть, делает примерно то же, что и if внутри скобок. На практике такая проверка нужна часто, а empty() удобна тем, что не генерирует варнинг. И можно не заморачиваться предварительным объявлением переменной. В документации это прекрасно описано. Мне казалось, это даже коты знают, а поди ж ты. :)
Я сейчас не об этом писал, вы вырвали две фразы из разных контекстов, про функцию isset, говорилось в контексте тренарной операции, а не if, и второй момент не подходит если я хочу чтобы значение 0 например присвоилось и не проигнорировалось и взялось дефолтное…
и второй момент не подходит если я хочу чтобы значение 0 например присвоилось и не проигнорировалось и взялось дефолтное…

Ничего не понял. Сдаюсь. :)
$value = empty($_GET['limit']) ? $_GET['limit'] : 10;


если $_GET['limit'] будет равно нулю, то $value будет равно 10, но я хочу, чтобы было 0, в этих случаях empty не подходит, а isset — да
UFO just landed and posted this here
const value = 0 || false || 'hello';
console.log(value); // hello

Это не будет работать в PHP, и эквивалентный код на PHP установит значение 0

Хм…
const value = 0 || false || 'hello';
console.log(value);
VM114:2 hello

onotole@home:~$ php
<?php
$value = 0 || false || 'hello';
var_dump($value);    
print_r(phpversion());
bool(true)
7.2.7-0ubuntu0.18.04.2

Жабаскрипт отдает строку хелло, но это его заморочки, по булевой логике должно быть true.
Что и делает наш любимый седьмой пых. :)
Я думаю имелось ввиду, что оператор ?? в пхп, почти эквивалентен джсному ||, но пхп проверяет только на null, т е:
echo 0 ?? false ?? 'hello';
echo null ?? $null ?? 'hello';

0hello

в джс немного по другому…
Кстати.
<?php
$value = 0 ?: false ?: 'hello';
var_dump($value); // string(5) "hello"


3v4l.org/fFm3U
да, но если вставить этот вариант в ваш пример то он выдаст нотис:
echo null ?: $null ?: 'hello';


а в джс вроде отработает как надо

Так тчо тут использование по ситуации
ну тогда так)
echo null ?: $null ?? false ?: 'hello';
Константные массивы

Еще в 5.6 появилось.
Статья запоздала на пару лет как минимум.
Когда люди обсуждают изменения в PHP7

Нормальные программисты давно уже обсуждают изменения в PHP 8.
И стараются не использовать define()

предлагает два разных объявления типов

Никакого «объявления типов» здесь нет. Это рантайм контроль типов.
И не «сообщение об ошибке», а исключение.

Безграмотная статья.
UFO just landed and posted this here
Совершенно бессмысленная глобальщина же. Код:
Заголовок спойлера
define('COLOR_RED', '#f44141');
define('COLOR_BLUE', '#4286f4');
define('COLOR_GREEN', '#1ae01e');
define('COLOR_PURPLE', '#f309f7');
define('COLOR_ORANGE', '#ef7700');


Запросто заменяется на:
Заголовок спойлера
class Colour 
{
    public const RED = '#f44141';
    public const BLUE = '#4286f4';
    public const GREEN = '#1ae01e';
    public const PURPLE = '#f309f7';
    public const ORANGE = '#ef7700';
}


О преимуществах второго варианта перед первым стоит упоминать?
Стоит упоминать, что мы не всегда используем классы, или вынуждены использовать define по ряду другим причин? не вижу смысла полностью списывать его со счетов…
«мы» — это кто? И почему «вынуждены»? Кто-то запрещает это делать? Я лично вообще не помню когда последний раз писал 10ти-строчные скриптики, где классы были бы просто оверинжинерингом.
Херня, я довольно часто пишу 20-строчные парсеры какой-нить херни, где сам парсер таки класс, и не вижу в этом оверинжиниринга. Просто класс в этом же файле :-)
У второго варианта есть как плюсы, так и минусы.
Ваше предложение, по сути, аналогично предложению заменить isset на empty (см. первый комментарий).
define удобен для конфигов. Например DEBUG, ENV.
define() работает в рантайме, const — конструкция этапа компиляции. Стоит ли говорить, что второе предпочтительнее?
Вы еще скажите что АОТ лучше чем JIT, только потому что одно заранее все полностью перелопатит, а второе по требованию. Или скажите что lazy loading это полная ересь, и ее использовать ни в коем случае не стоит. Стоит ли говорить что вы глупость сказали?
Не передёргивайте пожалуйста. Определение данных и структур во время компиляции, JIT и lazy loading — это как путать тёплое с мягким. Совершенно разные технологии, предназначенные для разного и решающие разные задачи. Это во-первых.

Во-вторых, ваш тон и тон Алекса Леонова черезчур категоричен. Пожалуй, что стоило бы для начала разобраться в чём разница между const и define(). Какие есть плюсы и минусы. Пожалуй, лучше всего ответил на этот вопрос Никита Попов (один из разработчиков ядра PHP): https://stackoverflow.com/a/3193704

В третьих, так да, const определённо лучше, чем define хотя бы потому, что значение константы инлайнится (в пределах файла, где происходит определение константы) и лучше поддаётся оптимизации OpCache благодаря возможности константных вычислений во время компиляции, а не в рантайме, что, допустим, может привести к меньшему количеству опкодов и более эффективному использованию буфера interned strings (не знаю как правильно на русский перевести).

В-четвёртых, в свете реализованных некоторых SSA-оптимизаций конструкция const может (именно может, но не факт) работать опять-таки благодаря константным выражениям и как следствие раскрутки и слопыванию узлов AST.

В-пятых, постарайтесь не быть настолько категоричным и фанатичным. Это я отношу как к вам, так и к Алексу Леонову.
Я ни в коем случае не уверждал обратного, я лишь сказал что фраза «Стоит ли говорить, что второе предпочтительнее?» — глупость. Так как не всегда этап компиляции предпочтительней, перед рантаймом. Как ни крутите а код в рантайме исполняется, и пхп при этом нормально себя чувствует. По сравнению с основным кодом количество констант описаных с помошью define крайне мало, и это не затронет производительности (это ведь не основное действие в коде — установка констант?).
А за ссылку спасибо, она явно объективней чем ответ Алекса.
И не «сообщение об ошибке», а исключение.

С каких пор fatal error стало исключением?
тем более, что вы не отловите его с помощью класса \Exception, только \Error ну и \Throwable само собой…
Fatal error здесь потому, что исключение не было поймано. Вам никто не мешает его поймать.
странные вещи вы пишите, ок вот вам примеры тогда:

\Exception не ловится
sandbox.onlinephpfunctions.com/code/27f7043b880d9cdcc5de067b17243972514b75e1

\Error все ок
sandbox.onlinephpfunctions.com/code/2b97205a8f3cb8a354abeaf9917718484e1210d9

ну и второй момент ексепшен не прерывает выполнение, а фатал — прерывает, можете проверить сами, здесь прерывается…
Прерывает только в том случае, если находится в том же файле, где и возникает ошибка. Т.е. вариант:
try {
    require __DIR__ . '/any-bad-code.php';
} catch (\Error $e) {
    echo $e;
}

\var_dump('ALL OK');


Будет работать даже тогда, когда в подключаемом файле синтаксические ошибки. Вообще при любых обстоятельствах.

Т.е. с точки зрения именования любые Throwable/Error — это ошибки с разным уровнем «страшности», а с точки зрения семантики и поведения — это обычные исключения.
тот факт, что фаталы, теперь можно отловить в блоке тру кач, не делает их еквивалентными, для этого и есть раздельные классы, чтобы их отловить, почитайте описание, там ясно сказано, что один отловливает ошибки, второй ексепшены…

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

Ну и опять же называть ошибку исключением у меня язык не повернется…
Вы меня простите, но у вас каша какая-то в голове. Ничего личного, извините.

Итак, у нас есть интерфейс Throwable. Это общий интерфейс для всех объектов, которые можно выбросить (throw) и поймать (catch).

Далее есть два класса, реализующих этот интерфейс: Error (для исключений системных) и Exception (для пользовательских). От первого наследуется большое количество системных исключений, вроде TypeError, от второго тоже немало, например InvalidArgumentException.

Важно понимать, что Error — это не ошибка. Это класс исключений, который называется «Error».

Что такое ошибки в PHP можно почитать здесь: php.net/manual/ru/errorfunc.constants.php

Почему же мы видим всё-таки ошибку Fatal error? Потому что не поймали исключение! Обратите внимание, что любое исключение, хоть наследующееся от Error, хоть от Exception, если вы его не отловите с помощью catch, всплывет по стеку вызовов до самого верха и вызовет фатальную ошибку.

Вот и всё.

Резюме:
— Error это не «ошибка», а класс исключений, называющийся «Error»
— Любой Throwable можно поймать, в том числе и любой Error
— Ошибки в PHP — не исключения, это совсем другой механизм
— Фатальная oшибка неизбежно возникает, если вы упустили любой Throwable
Я прекрасно вас понимаю, и тут дело только в терминологии, и с моей точки зрения, назвать это ошибкой тоже правильно, и вот например если вы откроете описание того же класса \Error, то там как раз таки пишеться про ошибки…

php.net/manual/ru/class.error.php
Базовый класс исключений для внутренних ошибок PHP.
Я не вижу никакого противоречия.

Внутри PHP возникает некая ошибка, он создает и выбрасывает исключение соответствующего класса.

Да, согласен, терминология может запутать.
Исключение — это не только Exception и его наследники, но всё, что реализует Throwable.
Нормальные программисты давно уже обсуждают изменения в PHP 8.

Не подскажете ссылку на почитать? Что-то ничего кроме статей про новый JIT не гуглится
У меня у одного складывается ощущение, что российское широкое сообщество PHP слегка более продвинутое, чем зарубежное?
если дальше русскоязычного хабра никуда не ходить, то именно такое ощущение и сложится.
в своё время мне очень помогли константы с ключами
Групповые Use Declarations


Надеюсь это не получит широкого распространения, т.к. поиск по проекту без IDE станет невозможным. (А с легаси кодом бывает так, что и с IDE не удается найти использования класса без полного поиска по проекту)
Тогда уже не «Null Оператор ??», а «Null coalescing оператор ??».
Sign up to leave a comment.

Articles