如何避免isset()和empty()

Pek*_*ica 96 php error-reporting

我有几个较旧的应用程序,当在E_NOTICE错误级别上运行时会抛出大量"xyz未定义"和"未定义的偏移"消息,因为没有使用isset()和consorts 显式检查变量的存在.

我正在考虑通过它们来使它们与E_NOTICE兼容,因为关于缺失变量或偏移的通知可以是救生员,可能会获得一些微小的性能改进,并且它总体上更清洁.

但是,我不喜欢对我的代码造成数百isset() empty()array_key_exists()s的影响.它变得臃肿,变得不那么可读,没有在价值或意义上获得任何东西.

如何在没有过多变量检查的情况下构建代码,同时还兼容E_NOTICE?

dec*_*eze 127

对于那些感兴趣的人,我已经将这个主题扩展为一篇小文章,它以更好的结构化形式提供了以下信息:PHP的权威指南isset和空


恕我直言,你应该考虑不只是使应用程序"E_NOTICE兼容",而是重组整个事情.在代码中有数百个点经常尝试使用不存在的变量听起来像一个结构相当糟糕的程序.尝试访问不存在的变量永远不应该发生,其他语言在编译时就不会这样做了.PHP允许你这样做的事实并不意味着你应该这样做.

这些警告可以帮助你,而不是惹恼你.如果你收到警告"你正在尝试使用不存在的东西!" ,你的反应应该是"哎呀,我的坏,让我尽快解决." 你怎么能分辨出"工作得很好的变量"真正错误的代码之间的区别可能会导致严重错误?这也是您始终始终将错误报告转换为11并继续插入代码直到没有NOTICE发布单一内容的原因.关闭错误报告仅适用于生产环境,以避免信息泄漏并提供更好的用户体验,即使面对错误的代码.


详细说明:

您将始终需要issetempty在代码中的某个位置,减少其发生的唯一方法是正确初始化变量.根据具体情况,有不同的方法:

函数参数:

function foo ($bar, $baz = null) { ... }
Run Code Online (Sandbox Code Playgroud)

有没有必要检查是否$bar$baz设置里面的功能,因为你设置它们,你需要担心的是,如果他们的价值评估为truefalse(或任何其他).

任何地方常规变量

$foo = null;
$bar = $baz = 'default value';
Run Code Online (Sandbox Code Playgroud)

在您要使用它们的代码块的顶部初始化变量.这解决了这个!isset问题,确保您的变量始终具有已知的默认值,让读者了解以下代码的工作原理,从而也可以作为一种自我文档.

阵列:

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

与上面相同,您使用默认值初始化数组并使用实际值覆盖它们.

在其余的情况下,假设您输出可能由控制器设置或未设置的值的模板,您只需要检查:

<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>
Run Code Online (Sandbox Code Playgroud)

如果您发现自己经常使用array_key_exists,则应评估您正在使用它的内容.它唯一有意义的是:

$array = array('key' => null);
isset($array['key']); // false
array_key_exists('key', $array); // true
Run Code Online (Sandbox Code Playgroud)

如上所述,如果您正确初始化变量,则无需检查密钥是否存在,因为您知道密钥是否存在.如果您收到来自外部源的阵列,该值将最有可能不是null,但是'',0,'0',false或类似的东西,即价值,你可以用评估isset或者empty,这取决于你的意图.如果你经常设置一个数组键,null并希望它具有任何意义,但是false,如果在上面的例子中,你的程序逻辑的不同结果issetarray_key_exists差异,你应该问问自己为什么.变量的存在不应该是重要的,只有它的价值应该是重要的.如果密钥是true/ falseflag,则使用truefalse不使用null.唯一的例外是想要null表达某些东西的第三方库,但由于null在PHP中很难检测到,我还没有找到任何这样做的库.

  • 我想不出任何我使用`array_key_exists`而不是简单的`isset($ array ['key'])`或`!empty($ array ['key'])`的情况.当然,两者都会在代码中添加7或8个字符,但我很难称之为问题.它也有助于澄清你的代码:`if(isset($ array ['key']))`意味着这个变量确实是可选的并且可能不存在,而`if($ array ['key'])`只是意味着"如果是真的".如果你收到后者的通知,你知道你的逻辑被搞砸了. (9认同)
  • 我相信isset()和array_key_exists()之间的区别在于,如果值为NULL,后者将返回true.isset()不会. (6认同)
  • 没错,但大多数失败的访问尝试都是`if($ array ["xyz"])`而不是`isset()`或`array_key_exists()`,我发现它有点合法,当然不是结构问题(纠正我)如果我错了)添加`array_key_exists()`对我来说似乎是一种可怕的浪费. (4认同)

Bal*_*usC 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以用作

$username = get_string($_POST, 'username');
Run Code Online (Sandbox Code Playgroud)

做同样的琐碎的东西一样get_number(),get_boolean(),get_array()等等.

  • 这看起来不错,并且也会进行magic_quotes检查.太好了! (5认同)
  • 请注意$ _POST ['something']可能会返回数组,例如输入`<input name ="something []"/>`.这会导致错误(因为修剪不能应用于数组)使用上面的代码,在这种情况下,应该使用`is_string`和可能'strval`.这不仅仅是一个人应该使用`get_array`的情况,因为用户输入(恶意)可能是任何东西,用户输入解析器永远不应该抛出错误. (3认同)

Jam*_*mol 13

我相信解决这个问题的最佳方法之一是通过类访问GET和POST(COOKIE,SESSION等)数组的值.

为每个数组创建一个类,声明__get__set方法(重载).__get接受一个参数,它将是一个值的名称.此方法应使用isset()或检查相应全局数组中的此值,empty()如果存在,则返回该值,否则返回null(或某些其他默认值).

之后,您可以以这种方式自信地访问数组值:$POST->username如果需要,可以在不使用任何isset()s或empty()s的情况下进行任何验证.如果username在相应的全局数组中不存在null则将返回,因此不会生成警告或通知.


Ali*_*xel 6

我不介意使用array_key_exists(),其实我更喜欢使用这个特定的功能,而不是依靠黑客可能会改变他们的行为在未来的功能emptyisset(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;
}
Run Code Online (Sandbox Code Playgroud)

假设你有以下数组:

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

$arr2 = array
(
    'x' => array
    (
        'y' => array
        (
            'z' => 'value',
        ),
    ),
);
Run Code Online (Sandbox Code Playgroud)

你如何从阵列中获得"价值"?简单:

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');
Run Code Online (Sandbox Code Playgroud)

我们已经覆盖了大学和多维数组,我们还能做些什么呢?


以下面的代码为例:

$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';
}
Run Code Online (Sandbox Code Playgroud)

很无聊不是吗?这是另一种使用该Value()功能的方法:

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

作为另一个例子,RealIP()一个测试函数:

$ip = Value($_SERVER, 'HTTP_CLIENT_IP', Value($_SERVER, 'HTTP_X_FORWARDED_FOR', Value($_SERVER, 'REMOTE_ADDR')));
Run Code Online (Sandbox Code Playgroud)

整洁,对吧?;)

  • "依赖可能改变未来行为的黑客功能"?!对不起,但这是我整周听到的最荒谬的事情.首先,`isset`和`empty`是*语言结构*,而不是函数.其次,如果**任何**核心库函数/语言结构改变了它们的行为,你可能会或可能不会被搞砸.如果`array_key_exists`改变了它的行为怎么办?答案是它不会,只要你按照文件记录使用它.并且``isset`被记录为完全如此使用.最坏的案例函数在主要版本或两个版本上弃用.NIH综合症很糟糕! (6认同)
  • 我说`isset`和`empty`并不比`array_key_exists`更可靠或更不可靠,并且可以做同样的工作.你的第二个冗长的例子可以写成`$ domain = isset($ domain ['host'])?$ domain ['host']:'N/A';`只有核心语言特性,不需要额外的函数调用或声明(请注意,我不一定主张使用三元运算符; o)).对于普通的标量变量,您仍然需要使用`isset`或`empty`,并且可以以完全相同的方式将它们用于数组."可靠性"是不这样做的一个坏理由. (3认同)
  • 虽然@deceze对自定义函数有一个观点 - 我通常采取相同的立场 - 值()方法看起来很有趣,我将会看一下它.我认为答案和后续工作将使所有偶然发现它的人能够自己决定.+1. (2认同)