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

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

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

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

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

11 ответов


для тех, кто заинтересован, я расширил эту тему в небольшую статью, которая предоставляет приведенную ниже информацию в несколько лучшей структурированной форме:окончательное руководство по isset PHP и пустой


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

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


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

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() и так далее.


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

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

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


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


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

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');

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


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

$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')));

прикольно, да? ;)


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


Я использую эти функции

function load(&$var) { return isset($var) ? $var : null; }
function POST($var) { return isset($_POST[$var]) ? $_POST[$var] : null; }

примеры

$y = load($x); // null, no notice

// this attitude is both readable and comfortable
if($login=POST("login")) // really =, not ==
if($pass=POST("pass"))
if($login=="Admin" && $pass==...) {
  // login and pass are not empty, login is "Admin" and pass is ...
  $authorized = true;
  ...
}

сделайте функцию, которая возвращает false если не установлено, и, если указано, false если пустой. Если valid возвращает переменную. Вы можете добавить дополнительные параметры, как показано в коде ниже:

<?php
function isset_globals($method, $name, $option = "") {
    if (isset($method[$name])) {    // Check if such a variable
        if ($option === "empty" && empty($method[$name])) { return false; } // Check if empty 
        if ($option === "stringLength" && strlen($method[$name])) { return strlen($method[$name]); }    // Check length of string -- used when checking length of textareas
        return ($method[$name]);
    } else { return false; }
}

if (!isset_globals("$_post", "input_name", "empty")) {
    echo "invalid";
} else {
    /* You are safe to access the variable without worrying about errors! */
    echo "you uploaded: " . $_POST["input_name"];
}
?>

Добро пожаловать в оператор null coalescing:

$field = $_GET['field'] ?? null;

в PHP говорит:

оператор коалесцирования null (??) был добавлен в качестве синтаксического сахара для общего случая необходимости использования Троицы в сочетании с isset (). Он возвращает первый операнд, если он существует и не равен NULL; в противном случае возвращается второй операнд.


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


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


Как насчет использования оператора@? например:

if(@$foo) { /* do something */ }

вы можете сказать, что это плохо, потому что у вас нет контроля над тем, что происходит "внутри" $foo (если это был вызов функции, который содержит ошибку PHP, например), но если вы используете этот метод только для переменных, это эквивалентно:

if(isset($foo) && $foo) { /* ... */ }