У меня есть несколько старых приложений, которые выдают много сообщений «xyz is undefined» и «undefined offset» при работе на уровне ошибки E_NOTICE, потому что наличие переменных не проверяется явно с помощью isset()
и consorts.
Я подумываю о работе над ними, чтобы сделать их совместимыми с E_NOTICE, поскольку уведомления об отсутствующих переменных или смещениях могут быть спасением, могут быть некоторые незначительные улучшения производительности, и в целом это более чистый способ.
Однако мне не нравится то, что делают с моим кодом сотни isset()
empty()
и array_key_exists()
. Он раздувается, становится менее читаемым, не приобретая ничего с точки зрения ценности или смысла.
Как я могу структурировать свой код без лишних проверок переменных, оставаясь при этом совместимым с E_NOTICE?
источник
Ответы:
Для тех, кто заинтересован, я расширил эту тему до небольшой статьи, в которой приведенная ниже информация представлена в несколько лучше структурированной форме: Полное руководство по isset PHP и пусто
ИМХО, вам следует подумать не просто о том, чтобы сделать приложение «совместимым с E_NOTICE», а о реструктуризации всего этого. Наличие сотен точек в вашем коде, которые регулярно пытаются использовать несуществующие переменные, звучит как довольно плохо структурированная программа. Попытки получить доступ к несуществующим переменным никогда не должны происходить, другие языки отказываются от этого во время компиляции. Тот факт, что PHP позволяет вам это делать, не означает, что вы должны это делать.
Эти предупреждения призваны помочь вам, а не раздражать вас. Если вы получаете предупреждение «Вы пытаетесь работать с тем, чего не существует!» , ваша реакция должна быть "Ой, моя проблема, позвольте мне исправить это как можно скорее". Как еще вы собираетесь отличить «переменные, которые прекрасно работают без определения» и действительно неправильный код, который может привести к серьезным ошибкам ? Это также причина, по которой вы всегда, всегда разрабатываете с отчетом об ошибках, обращенным к 11, и продолжаете работать над своим кодом, пока не останется ни одного
NOTICE
выпущен. Отключение отчетов об ошибках предназначено только для производственных сред, чтобы избежать утечки информации и улучшить взаимодействие с пользователем даже при наличии ошибок в коде.Чтобы уточнить:
Вы всегда будете нуждаться
isset
илиempty
где-то в вашем коде, единственный способ уменьшить их появление - правильно инициализировать ваши переменные. В зависимости от ситуации это можно сделать разными способами:Аргументы функции:
Нет необходимости проверять, установлены ли
$bar
или$baz
внутри функции, потому что вы просто устанавливаете их, все, о чем вам нужно беспокоиться, это оценивать их значение какtrue
илиfalse
(или что-то еще).Обычные переменные где угодно:
Инициализируйте свои переменные в верхней части блока кода, в котором вы собираетесь их использовать. Это решает
!isset
проблему, гарантирует, что ваши переменные всегда имеют известное значение по умолчанию, дает читателю представление о том, над чем будет работать следующий код, и тем самым также служит своего рода самодокументированием.Массивы:
То же, что и выше, вы инициализируете массив значениями по умолчанию и перезаписываете их фактическими значениями.
В остальных случаях, скажем, шаблон, в котором вы выводите значения, которые могут или не могут быть установлены контроллером, вам просто нужно проверить:
Если вы обнаружите, что регулярно используете
array_key_exists
, вам следует оценить, для чего вы его используете. Единственный раз, когда это имеет значение, здесь:Однако, как указано выше, если вы правильно инициализируете свои переменные, вам не нужно проверять, существует ли ключ или нет, потому что вы знаете, что это так. Если вы получаете массив из внешнего источника, то значение будет , скорее всего , не будет ,
null
но''
,0
,'0'
,false
или нечто подобное, то есть значение , которое можно оценить сisset
илиempty
, в зависимости от вашего намерения. Если вы регулярно устанавливаете ключ массива в значениеnull
и хотите, чтобы он означал что угодно, ноfalse
, например, если в приведенном выше примере разные результатыisset
иarray_key_exists
имеют значение для логики вашей программы, вы должны спросить себя, почему. Само существование переменной не должно иметь значения, важно только ее значение. Если ключ - этоtrue
/false
flag, используйтеtrue
илиfalse
нетnull
. Единственным исключением из этого правила могут быть сторонние библиотеки, которые хотятnull
что-то значить, но, поскольку ихnull
так сложно обнаружить в PHP, мне еще предстоит найти какую-либо библиотеку, которая это делает.источник
if ($array["xyz"])
вместоisset()
илиarray_key_exists()
которые я считаю в некоторой степени законными, определенно не структурными проблемами (поправьте меня, если я ошибаюсь). Добавлениеarray_key_exists()
для меня выглядит ужасной тратой.array_key_exists
вместо простогоisset($array['key'])
или!empty($array['key'])
. Конечно, оба добавляют в код 7 или 8 символов, но я бы не назвал это проблемой. Это также помогает прояснить ваш код:if (isset($array['key']))
означает, что эта переменная действительно необязательна и может отсутствовать, тогдаif ($array['key'])
как означает просто «если истина». Если вы получите уведомление о последнем, вы знаете, что ваша логика где-то облажалась.Просто напишите для этого функцию. Что-то вроде:
который вы можете использовать как
Сделайте то же самое для тривиальной вещи , как
get_number()
,get_boolean()
,get_array()
и так далее.источник
<input name="something[]" />
. Это вызовет ошибку (поскольку обрезка не может применяться к массивам) с использованием приведенного выше кода, в этом случае следует использоватьis_string
и, возможноstrval
. Это не просто тот случай, когда следует использоватьget_array
либо одно, либо другое, поскольку пользовательский ввод (вредоносный) может быть чем угодно, а синтаксический анализатор пользовательского ввода в любом случае никогда не должен выдавать ошибку.Я считаю, что одним из лучших способов справиться с этой проблемой является доступ к значениям массивов GET и POST (COOKIE, SESSION и т. Д.) Через класс.
Создайте класс для каждого из этих массивов и объявите
__get
и__set
методы ( перегрузка ).__get
принимает один аргумент, который будет именем значения. Этот метод должен проверять это значение в соответствующем глобальном массиве, используяisset()
или,empty()
и возвращать значение, если оно существует, илиnull
(или какое-либо другое значение по умолчанию) в противном случае.После этого вы можете уверенно обращаться к значениям массива следующим образом:
$POST->username
и при необходимости выполнять любую проверку без использования каких-либоisset()
s илиempty()
s. Еслиusername
не существует в соответствующем глобальном массиве, тоnull
будет возвращено, поэтому никаких предупреждений или уведомлений не будет.источник
Я не против использовать эту
array_key_exists()
функцию. Фактически, я предпочитаю использовать эту конкретную функцию, а не полагаться на функциивзлома,которые могут изменить свое поведение в будущем,например(зачеркнуто, чтобы избежать уязвимостей ).empty
иisset
Однако я использую простую функцию, которая пригодится в этой и некоторых других ситуациях при работе с индексами массива :
Допустим, у вас есть следующие массивы:
Как получить «значение» из массивов? Просто:
У нас уже есть одномерные и многомерные массивы, что еще мы можем сделать?
Возьмем, к примеру, следующий фрагмент кода:
Довольно скучно, правда? Вот еще один подход с использованием
Value()
функции:В качестве дополнительного примера возьмем
RealIP()
функцию для теста:Аккуратно, а? ;)
источник
isset
иempty
являются языковыми конструкциями , а не функции. Во-вторых, если какие-либо базовые библиотечные функции / языковые конструкции изменят свое поведение, вы можете оказаться в затруднительном положении. Что, еслиarray_key_exists
изменится его поведение? Ответ - не будет, пока вы используете его, как описано в документации. Иisset
задокументирован для использования именно так. Функции наихудшего случая считаются устаревшими по сравнению с одной или двумя основными версиями. Синдром НИЗ - это плохо!array_key_exists()
проверку наличия ключа в массиве ?!array_key_exists()
была создана именно для этого , я скорее полагаться на него для этой цели , чемisset()
и специальноempty()
чье официальное описание: «определить , является ли пустая переменная», не упоминает ничего , если она на самом деле существует. Ваш комментарий и голос "против" - одни из самых нелепых, которые я видел за весь месяц .isset
иempty
не более или менее надежны , чемarray_key_exists
и может сделать точно такую же работу. Ваш второй, многословный пример может быть написан$domain = isset($domain['host']) ? $domain['host'] : 'N/A';
с использованием только основных языковых функций, без дополнительных вызовов функций или объявлений (обратите внимание, что я не обязательно выступаю за использование тернарного оператора; о)). Для обычных скалярных переменных вам все равно нужно будет использоватьisset
илиempty
, и вы можете использовать их для массивов точно так же. «Надежность» - плохая причина для того, чтобы этого не делать.Я здесь с тобой. Но дизайнеры PHP сделали гораздо более худших ошибок, чем это. Если не считать определения пользовательской функции для чтения любого значения, другого пути нет.
источник
params["width"] = params["width"] || 5
для установки значений по умолчанию вместо всей этой ерунды сisset()
вызовами.register_globals
иmagic_quotes
. Эти проблемы делают неинициализированные переменные почти безобидными по сравнению с ними.Я использую эти функции
Примеры
источник
Добро пожаловать в оператор объединения с нулевым значением (PHP> = 7.0.1):
PHP говорит:
источник
Создайте функцию, которая возвращает,
false
если не задана, и, если она указана,false
если она пуста. Если верно, он возвращает переменную. Вы можете добавить дополнительные параметры, как показано в приведенном ниже коде:источник
Программное обеспечение не запускается волшебным образом по милости божьей. Если вы ожидаете чего-то, чего не хватает, нужно правильно с этим справиться.
Если вы игнорируете это, вы, вероятно, создаете дыры в безопасности в своих приложениях. В статических языках доступ к неопределенной переменной просто невозможен. Он не просто скомпилирует или завершит работу вашего приложения, если оно пустое.
Более того, это делает ваше приложение недоступным для обслуживания, и вы сходите с ума, когда случаются неожиданные вещи. Строгость языка является обязательной, и PHP изначально ошибочен во многих аспектах. Если вы не знаете, из вас получится плохой программист.
источник
Я не уверен, каково ваше определение читабельности, но правильное использование блоков empty (), isset () и try / throw / catch очень важно для всего процесса.
Если ваш E_NOTICE поступает из $ _GET или $ _POST, тогда они должны быть проверены на empty () вместе со всеми другими проверками безопасности, которые эти данные должны пройти.
Если он поступает из внешних каналов или библиотек, он должен быть заключен в файл try / catch.
Если он поступает из базы данных, следует проверить $ db_num_rows () или его эквивалент.
Если он исходит от внутренних переменных, они должны быть правильно инициализированы. Часто эти типы уведомлений приходят из-за присвоения новой переменной возвращаемого значения функции, которая возвращает FALSE в случае сбоя. Они должны быть заключены в тест, который в случае сбоя может либо присвоить переменной приемлемое значение по умолчанию, которое может обработать код, либо выдать исключение, которое может обработать код.
Эти вещи делают код длиннее, добавляют дополнительные блоки и дополнительные тесты, но я не согласен с вами в том смысле, что я думаю, что они определенно добавляют дополнительную ценность.
источник
А как насчет использования
@
оператора?Например:
Вы можете сказать, что это плохо, потому что вы не контролируете, что происходит «внутри» $ foo (например, если это был вызов функции, содержащий ошибку PHP), но если вы используете этот метод только для переменных, это эквивалентно:
источник
if(isset($foo))
на самом деле достаточно. Он вернется,TRUE
если выражение оценивается какTRUE
.