提问人:Pekka 提问时间:12/25/2009 最后编辑:Pekka 更新时间:8/18/2020 访问量:26380
如何避免 isset() 和 empty()
How to avoid isset() and empty()
问:
我有几个较旧的应用程序在E_NOTICE错误级别运行时会抛出大量“xyz is undefined”和“undefined offset”消息,因为没有使用 和 consorts 显式检查变量的存在。isset()
我正在考虑通过它们使它们E_NOTICE兼容,因为关于缺少变量或偏移量的通知可以挽救生命,可能会获得一些小的性能改进,而且总体上是更干净的方式。
但是,我不喜欢对我的代码施加数百个和 s 的影响。它变得臃肿,变得不那么可读,在价值或意义方面没有任何收获。isset()
empty()
array_key_exists()
如何在不进行过多变量检查的情况下构建代码,同时又E_NOTICE兼容?
答:
只需为此编写一个函数即可。像这样:
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()
评论
<input name="something[]" />
is_string
strval
get_array
对于那些感兴趣的人,我已将这个主题扩展为一篇小文章,它以结构更好的形式提供了以下信息: PHP isset 的权威指南 和空的
恕我直言,您不仅应该考虑使应用程序“E_NOTICE兼容”,还应该考虑重组整个事情。在代码中有数百个点经常尝试使用不存在的变量,这听起来像是一个结构相当糟糕的程序。尝试访问不存在的变量永远不应该发生,其他语言在编译时对此犹豫不决。PHP允许你这样做的事实并不意味着你应该这样做。
这些警告是为了帮助你,而不是为了惹恼你。如果你收到警告“你正在尝试使用不存在的东西!”,你的反应应该是“哎呀,我的错,让我尽快修复它。你怎么能区分“未定义工作的变量”和可能导致严重错误的错误代码?这也是为什么你总是,总是,在开发时将错误报告调到11,并不断插入你的代码,直到没有一个发出。关闭错误报告仅适用于生产环境,以避免信息泄露,即使在面对有缺陷的代码时也能提供更好的用户体验。NOTICE
详细说明:
您将始终需要或在代码中的某个地方,减少它们出现的唯一方法是正确初始化变量。根据具体情况,有不同的方法可以做到这一点:isset
empty
函数参数:
function foo ($bar, $baz = null) { ... }
无需检查函数内部是否设置了 or,因为您只需设置它们,您需要担心的是它们的值是否计算为 or(或其他任何值)。$bar
$baz
true
false
任何地方的常规变量:
$foo = null;
$bar = $baz = 'default value';
在要使用变量的代码块的顶部初始化变量。这解决了问题,确保变量始终具有已知的默认值,让读者了解以下代码将用于什么,从而也是一种自我文档。!isset
阵 列:
$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
如上所述,如果您正确地初始化了变量,则无需检查密钥是否存在,因为您知道它确实存在。如果您从外部源获取数组,则该值很可能不是 , , , 或类似的东西,即您可以根据自己的意图使用 或 计算的值。如果您经常将数组键设置为并希望它表示除 之外的任何含义,即如果在上面的示例中,不同的结果 和 对您的程序逻辑产生影响,您应该问自己为什么。变量的存在本身并不重要,只有它的值才有意义。如果键是 / 标志,则使用 或 ,而不是 。唯一的例外是想要表示某种含义的第三方库,但由于在 PHP 中很难检测到,我还没有找到任何这样做的库。null
''
0
'0'
false
isset
empty
null
false
isset
array_key_exists
true
false
true
false
null
null
null
评论
if ($array["xyz"])
isset()
array_key_exists()
array_key_exists()
array_key_exists
isset($array['key'])
!empty($array['key'])
if (isset($array['key']))
if ($array['key'])
我和你在一起。但是PHP设计者犯了比这更严重的错误。除了为任何值读取定义自定义函数之外,没有任何方法可以绕过它。
评论
params["width"] = params["width"] || 5
isset()
register_globals
magic_quotes
我不确定您对可读性的定义是什么,但正确使用 empty()、isset() 和 try/throw/catch 块对整个过程非常重要。
如果您的E_NOTICE来自 _GET 美元或 _POST 美元,那么应该根据 empty() 检查它们以及该数据必须通过的所有其他安全检查。
如果它来自外部源或库,则应将其包装在 try/catch 中。
如果它来自数据库,则应检查 $db_num_rows() 或其等效项。
如果它来自内部变量,则应正确初始化它们。通常,这些类型的通知来自将新变量分配给函数的返回值,该函数在失败时返回 FALSE。这些应该包装在一个测试中,在发生故障时,可以为变量分配代码可以处理的可接受默认值,也可以引发代码可以处理的异常。
这些东西使代码更长,添加额外的块,并添加额外的测试,但我不同意你的观点,因为我认为它们肯定会增加额外的价值。
我不介意使用这个功能。事实上,我更喜欢使用这个特定的函数,而不是依赖 hack 函数,这些函数将来可能会改变它们的行为,比如 (删除线以避免敏感性)。empty
和 isset
array_key_exists()
但是,我确实使用了一个简单的函数,该函数在这方面派上用场,并且在处理数组索引时还有其他一些情况:
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')));
整洁,是吧?;)
评论
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
软件不会神奇地靠上帝的恩典运行。如果您期待缺少某些东西,则需要妥善处理它。
如果忽略它,则可能会在应用程序中创建安全漏洞。在静态语言中,访问未定义的变量是不可能的。如果它为 null,它不会简单地编译或崩溃您的应用程序。
此外,它使您的应用程序无法维护,当意外事情发生时,您会发疯。语言的严格性是必须的,而PHP在设计上在很多方面都是错误的。如果你不知道,它会让你成为一个糟糕的程序员。
评论
我相信解决这个问题的最佳方法之一是通过类访问 GET 和 POST(COOKIE、SESSION 等)数组的值。
为每个数组创建一个类,并声明 and 方法(重载)。 接受一个参数,该参数将是一个值的名称。此方法应在相应的全局数组中检查此值,使用 或 并返回该值(如果存在)或(或其他默认值)否则。__get
__set
__get
isset()
empty()
null
之后,您可以放心地以这种方式访问数组值:并在需要时执行任何验证,而无需使用任何 s 或 s。如果相应的全局数组中不存在,则将返回,因此不会生成警告或通知。$POST->username
isset()
empty()
username
null
评论
我使用这些功能
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") and $pass=POST("pass")) { // really =, not ==
// executes only if both login and pass were in POST
// stored in $login and $pass variables
$authorized = $login=="root" && md5($pass)=="f65b2a087755c68586568531ad8288b4";
}
评论
使用运算符怎么样?@
例如:
if(@$foo) { /* Do something */ }
你可能会说这很糟糕,因为你无法控制“内部”$foo发生的事情(例如,如果它是一个包含 PHP 错误的函数调用),但如果你只对变量使用这种技术,这相当于:
if(isset($foo) && $foo) { /* ... */ }
评论
if(isset($foo))
其实就够了。如果表达式的计算结果为 。TRUE
TRUE
创建一个函数,如果未设置,则返回,如果指定,则返回空。如果有效,则返回变量。您可以添加更多选项,如下面的代码所示:false
false
<?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 合并运算符 (PHP >= 7.0.1):
$field = $_GET['field'] ?? null;
PHP 说道:
空合并运算符 (??) 已被添加为语法糖,用于需要将三元与 isset() 结合使用的常见情况。如果它存在且不为 NULL,则返回其第一个操作数;否则,它将返回其第二个操作数。
评论