Как избежать isset () и пустой ()

У меня есть несколько более старых приложений, которые бросают много из "xyz, неопределенное" и "неопределенное смещение" сообщения при работе ошибочного уровня E_NOTICE, потому что существование переменных явно не проверяется с помощью isset() и супруги.

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

Однако мне не нравится что причинение сотен isset() empty() и array_key_exists() s делает к моему коду. Это чрезмерно увеличено в размере, становится менее читаемым, ничего не получая с точки зрения значения или значения.

Как я могу структурировать свой код без избытка переменных проверок, также будучи совместимым E_NOTICE?

96
задан Pekka supports GoFundMonica 3 January 2016 в 06:29
поделиться

7 ответов

Для тех, кто интересуется, я расширил эту тему в маленькую статью, в которой представлена нижеприведенная информация в несколько более структурированной форме: Definitive Guide To PHP isset And empty


IMHO вам следует подумать не только о том, чтобы сделать приложение "E_NOTICE совместимым", но и о реструктуризации всего этого. Наличие в коде сотен пунктов, которые регулярно пытаются использовать несуществующие переменные, звучит как довольно плохо структурированная программа. Попытки получить доступ к несуществующим переменным никогда не должны происходить, другие языки в это время мешают при компиляции. Тот факт, что PHP позволяет это делать, не означает, что вы должны это делать.

Эти предупреждения предназначены для help вас, а не для того, чтобы вас раздражать. Если вы получаете предупреждение "Вы пытаетесь работать с чем-то, чего не существует!", то ваша реакция должна быть "Ой, виноват, давайте я исправлю этот ASAP". Как еще вы собираетесь отличать "переменные, которые работают просто отлично неопределенно" от , честно говоря, неправильного кода, который может привести к серьезным ошибкам? По этой же причине Вы всегда, всегда , развиваетесь с сообщением об ошибках , повернутым на 11 , и продолжаете подключаться к своему коду до тех пор, пока не будет выдано ни одного УВЕДОМЛЕНИЯ . Отключение сообщения об ошибках предназначено только для производственных сред, чтобы избежать утечки информации и обеспечить лучший пользовательский опыт даже перед лицом багги кода.


Для разработки:

Вам всегда будет нужен isset или пустой где-нибудь в Вашем коде, единственный способ уменьшить их появление - правильно инициализировать Ваши переменные. В зависимости от ситуации это можно сделать разными способами:

Аргументы функции:

function foo ($bar, $baz = null) { ... }

Нет необходимости проверять, установлено ли $bar или $baz внутри функции, так как Вы их просто устанавливаете, все, о чем Вам нужно беспокоиться, так это о том, вычисляется ли их значение в true или false (или что-то еще).

Обычные переменные где угодно:

$foo = null;
$bar = $baz = 'default value';

Инициализируйте свои переменные в верхней части блока кода, в котором вы собираетесь их использовать. Это решает проблему !isset, гарантирует, что Ваши переменные всегда будут иметь известное значение по умолчанию, дает читателю представление о том, над чем будет работать следующий код, и тем самым служит своего рода самодокументацией.

Arrays:

$defaults = array('foo' => false, 'bar' => true, 'baz' => 'default value');
$values = array_merge($defaults, $incoming_array);

Массивы:

$defaults = array('foo' => false, 'bar' => true, 'baz' => 'default value');
$values = array_merge($defaults, $incoming_array);

То же самое, что и выше, Вы инициализируете массив значениями по умолчанию и перезаписываете их реальными значениями.

В остальных случаях, скажем, в шаблоне, где вы выводите значения, которые могут задаваться или не задаваться контроллером, вам просто нужно проверить:

<table>
    <?php if (!empty($foo) && is_array($foo)) : ?>
        <?php foreach ($foo as $bar) : ?>
            <tr>...</tr>
        <?php endforeach; ?>
    <?php else : ?>
        <tr><td>No Foo!</td></tr>
    <?php endif; ?>
</table>

Если вы регулярно используете array_key_exists, то вы должны оценить, для чего вы его используете. Единственное время, когда это имеет значение - здесь:

$array = array('key' => null);
isset($array['key']); // false
array_key_exists('key', $array); // true

Как было сказано выше, если Вы правильно инициализируете свои переменные, Вам не нужно проверять, существует ли ключ или нет, потому что Вы знаете, что он существует. Если Вы получаете массив из внешнего источника, то скорее всего, значение будет не null, а ', 0, '0', false или что-то в этом роде, т.е. значение, которое Вы можете оценить с помощью isset или empty, в зависимости от Ваших намерений. Если Вы регулярно устанавливаете ключ массива на null и хотите, чтобы он означал что-либо, кроме false, т.е. если в приведенном выше примере различные результаты isset и array_key_exists вносят изменения в логику Вашей программы, то Вам следует спросить себя, почему. Само существование переменной не должно быть важным, только ее значение должно иметь значение. Если ключ имеет флаг true/false, то используйте true или false, а не null. Единственным исключением будут библиотеки третьих сторон, которые хотят, чтобы null что-то значил, но так как null так сложно обнаружить в PHP, я еще не нашел ни одной библиотеки, которая делает это.

.
127
ответ дан 24 November 2019 в 05:37
поделиться

Просто напиши для этого функцию. Что-то вроде:

function get_string($array, $index, $default = null) {
    if (isset($array[$index]) && strlen($value = trim($array[$index])) > 0) {
        return get_magic_quotes_gpc() ? stripslashes($value) : $value;
    } else {
        return $default;
    }
}

которую можно использовать как

$username = get_string($_POST, 'username');

Делайте то же самое для таких тривиальных вещей, как get_number(), get_boolean(), get_array() и так далее.

.
37
ответ дан 24 November 2019 в 05:37
поделиться

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

.
3
ответ дан 24 November 2019 в 05:37
поделиться

Я считаю, что один из лучших способов решения этой проблемы - это доступ к значениям массивов GET и POST (COOKIE, SESSION и т.д.) через класс.

Создайте класс для каждого из этих массивов и объявите методы __get и __set (перегрузка). __get принимает один аргумент, который будет именем значения. Этот метод должен проверить это значение в соответствующем глобальном массиве либо с помощью isset(), либо с помощью empty() и вернуть значение, если оно существует, либо null (или какое-либо другое значение по умолчанию) в противном случае.

После этого можно уверенно получить доступ к значениям массива таким образом: $POST-> имя пользователя и выполнить проверку, если необходимо, без использования каких-либо isset()s или empty() s. Если имя пользователя не существует в соответствующем глобальном массиве, то будет возвращен ноль, поэтому никаких предупреждений или уведомлений не будет выдано.

.
13
ответ дан 24 November 2019 в 05:37
поделиться

Я не возражаю против использования array_key_exists(), На самом деле я предпочитаю использовать эту специфическую функцию , а не полагаться на взломать функции, которые могут изменить свое поведение в будущем , такие как пустые и isset (пробиты, чтобы избежать восприимчивости ). Однако, я использую простую функцию, которая пригодится в этом и некоторых других ситуациях при работе с индексами массивов:

function Value($array, $key, $default = false)
{
    if (is_array($array) === true)
    {
        settype($key, 'array');

        foreach ($key as $value)
        {
            if (array_key_exists($value, $array) === false)
            {
                return $default;
            }

            $array = $array[$value];
        }

        return $array;
    }

    return $default;
}

Допустим, у вас есть следующие массивы:

$arr1 = array
(
    'xyz' => 'value'
);

$arr2 = array
(
    'x' => array
    (
        'y' => array
        (
            'z' => 'value',
        ),
    ),
);

Как вы получаете "значение" из массивов? Просто:

Value($arr1, 'xyz', 'returns this if the index does not exist');
Value($arr2, array('x', 'y', 'z'), 'returns this if the index does not exist');

У нас уже есть одно- и многомерные массивы, что еще можно сделать?


Возьмем, к примеру, следующий кусок кода:

$url = 'https://stackoverflow.com/questions/1960509';
$domain = parse_url($url);

if (is_array($domain) === true)
{
    if (array_key_exists('host', $domain) === true)
    {
        $domain = $domain['host'];
    }

    else
    {
        $domain = 'N/A';
    }
}

else
{
    $domain = 'N/A';
}

Довольно скучно, не правда ли? Вот еще один подход с использованием функции Value():

$url = 'https://stackoverflow.com/questions/1960509';
$domain = Value(parse_url($url), 'host', 'N/A');

В качестве дополнительного примера возьмем функцию RealIP() для теста:

$ip = Value($_SERVER, 'HTTP_CLIENT_IP', Value($_SERVER, 'HTTP_X_FORWARDED_FOR', Value($_SERVER, 'REMOTE_ADDR')));

Neat, huh? ;)

.
6
ответ дан 24 November 2019 в 05:37
поделиться

Я не уверен, какое у вас определение читабельности, но правильное использование пустой(), isset() и блоков try/throw/catch, очень важно для всего процесса. Если ваша E_NOTICE идет от $_GET или $_POST, то они должны быть проверены с помощью empty() вместе со всеми остальными проверками безопасности, которые должны пройти эти данные. Если она поступает из внешних каналов или библиотек, то ее следует обернуть в try/catch. Если они поступают из базы данных, то следует проверить $db_num_rows() или его эквивалент. Если они исходят из внутренних переменных, то их следует правильно инициализировать. Часто такие уведомления приходят от присваивания новой переменной возврату функции, которая возвращает FALSE при неудаче, они должны быть обернуты в тест, который в случае неудачи может либо присвоить переменной приемлемое значение по умолчанию, с которым может справиться код, либо бросить исключение, с которым может справиться код. Эти вещи делают код длиннее, добавляют дополнительные блоки и добавляют дополнительные тесты, но я не согласен с вами в том, что я думаю, что они определенно добавляют дополнительное значение

.
0
ответ дан 24 November 2019 в 05:37
поделиться

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

.
0
ответ дан 24 November 2019 в 05:37
поделиться
Другие вопросы по тегам:

Похожие вопросы: