【问题标题】:Check if value isset and null检查值是否为 isset 和 null
【发布时间】:2011-04-17 17:25:46
【问题描述】:

我需要检查 value 是否定义为任何内容,包括 null。 isset 将 null 值视为未定义并返回 false。以以下为例:

$foo = null;

if(isset($foo)) // returns false
if(isset($bar)) // returns false
if(isset($foo) || is_null($foo)) // returns true
if(isset($bar) || is_null($bar)) // returns true, raises a notice

请注意,$bar 未定义。

我需要找到一个满足以下条件的条件:

if(something($bar)) // returns false;
if(something($foo)) // returns true;

有什么想法吗?

【问题讨论】:

  • if(isset($foo)) // 返回 false,这些年来我从椅子上摔下来了……
  • in_array($key,array_keys($_SESSION)) && is_null($_SESSION[$key]) 我想了很久..
  • 这对我来说不是正常行为,isset = 已设置?,您的变量设置为 null。因为这个,我浪费了很多时间......
  • @VincentDecaux 它是 PHP...只是该语言中许多不合逻辑的事情的一个例子...

标签: php null isset


【解决方案1】:

IIRC,您可以为此使用get_defined_vars()

$foo = NULL;
$vars = get_defined_vars();
if (array_key_exists('bar', $vars)) {}; // Should evaluate to FALSE
if (array_key_exists('foo', $vars)) {}; // Should evaluate to TRUE

【讨论】:

  • +1 我打算建议相同的功能,get_defined_vars 很乐意应付范围。
  • 似乎可以工作,但我希望有更简单的东西。那好吧。让我们看看是否有人能想出一个班轮。
  • 好吧,你不需要 vars,所以理论上它只有一行 "if(array_key_exists('foo',get_defined_vars())){} "
  • fvn's newer answer 可能是获取当前上下文中存在的变量的更快方法,避免了get_defined_vars():array_key_exists('foo', compact('foo')) 的成本。或者更快,如果测试全局:array_key_exists('foo', $GLOBALS).
【解决方案2】:

如果您正在处理可能具有 NULL 值的对象属性,您可以使用:property_exists() 而不是 isset()

<?php

class myClass {
    public $mine;
    private $xpto;
    static protected $test;

    function test() {
        var_dump(property_exists($this, 'xpto')); //true
    }
}

var_dump(property_exists('myClass', 'mine'));   //true
var_dump(property_exists(new myClass, 'mine')); //true
var_dump(property_exists('myClass', 'xpto'));   //true, as of PHP 5.3.0
var_dump(property_exists('myClass', 'bar'));    //false
var_dump(property_exists('myClass', 'test'));   //true, as of PHP 5.3.0
myClass::test();

?>

与 isset() 不同,property_exists() 会返回 TRUE,即使该属性的值为 NULL。

【讨论】:

  • 您可以使用 array_key_exists(); 对数组执行相同操作
【解决方案3】:

Best way to test for a variable's existence in PHP; isset() is clearly broken

 if( array_key_exists('foo', $GLOBALS) && is_null($foo)) // true & true => true
 if( array_key_exists('bar', $GLOBALS) && is_null($bar)) // false &  => false

【讨论】:

  • 您引用的代码仅在变量在全局范围内时才有效。
  • 确实,但这不是最常见的情况吗?在函数中,您将拥有全局范围内的变量和参数(始终定义)。你也可以有对象属性,但是你可以使用'property_exists'。
  • 使用 $GLOBALS 似乎有点不稳定,我必须自己做一些测试才能将其声明为有效。
【解决方案4】:

我发现compact 是一个忽略未设置变量但确实对设置为null 的变量起作用的函数,因此当您有一个大型本地符号表时,我想您可以获得比检查@ 更有效的解决方案987654325@ 使用array_key_exists('foo', compact('foo')):

$foo = null;
echo isset($foo) ? 'true' : 'false'; // false
echo array_key_exists('foo', compact('foo')) ? 'true' : 'false'; // true
echo isset($bar) ? 'true' : 'false'; // false
echo array_key_exists('bar', compact('bar')) ? 'true' : 'false'; // false

更新

从 PHP 7.3 开始,compact() 将通知未设置的值,因此很遗憾,这种替代方法不再有效。

compact() 现在如果给定字符串引用未设置的变量,则会发出 E_NOTICE 级别错误。以前,这样的琴弦一直默默无闻 跳过。

【讨论】:

  • 有趣的选择。但请注意,它可能比在现有数组(例如 $GLOBALS)上调用 array_key_exists - 因为当表变大时,在哈希表中的查找不会变得更慢,而且你'我添加了compact 的额外工作。尽管如此,我还是赞成它,因为它在一种情况下很有用:如果你想知道foo 是否存在在当前上下文中,不管它来自哪里——如果你不在乎是否本地的还是全局的,只想知道是否存在。
  • @ToolmakerSteve - 我实际上指的是调用get_defined_vars 的潜在重大开销。见here
【解决方案5】:

我在寻找数组的解决方案时发现了这个主题。要检查是否存在包含 NULL 的数组元素,这种构造帮助了我

    $arr= [];
    $foo = 'foo';
    $arr[$foo]= NULL;
    if (array_key_exists('bar', $arr)) {}; // Should evaluate to FALSE
    if (array_key_exists('foo', $arr)) {}; // Should evaluate to TRUE
    if (array_key_exists($foo, $arr)) {}; // Should evaluate to TRUE

【讨论】:

    【解决方案6】:

    以下作为 PHP 扩展编写的代码等价于 array_key_exists($name, get_defined_vars())(感谢 Henrik 和 Hannes)。

    // get_defined_vars()
    // https://github.com/php/php-src/blob/master/Zend/zend_builtin_functions.c#L1777
    // array_key_exists
    // https://github.com/php/php-src/blob/master/ext/standard/array.c#L4393
    
    PHP_FUNCTION(is_defined_var)
    {
    
        char *name;
        int name_len;
    
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
            return;
        }
    
        if (!EG(active_symbol_table)) {
            zend_rebuild_symbol_table(TSRMLS_C);
        }
    
        if (zend_symtable_exists(EG(active_symbol_table), name, name_len + 1)) {
            RETURN_TRUE;
        }
    
    }
    

    【讨论】:

      【解决方案7】:

      您可以使用is_nullempty 代替isset()。如果变量不存在,empty 不会打印错误消息。

      【讨论】:

      • 我正在使用 is_null。无论isset如何,结果都是相同的。
      • 我在发布第一个答案时犯了一个错误:你尝试过 empty() 吗?
      • 这不适用于非空且非 NULL 的值,例如 FALSE、0、array() 或 ""。
      • 这个答案是错误的。 is_nullis_set有同样的问题:无法区分“未设置”和“设置为空”,这就是OP的问题。正如 Calum 指出的那样,empty 更糟。
      【解决方案8】:

      这里有一些使用 xdebug 的愚蠢解决方法。 ;-)

      function is_declared($name) {
          ob_start();
          xdebug_debug_zval($name);
          $content = ob_get_clean();
      
          return !empty($content);
      }
      
      $foo = null;
      var_dump(is_declared('foo')); // -> true
      
      $bla = 'bla';
      var_dump(is_declared('bla')); // -> true
      
      var_dump(is_declared('bar')); // -> false
      

      【讨论】:

      • 看起来不太便携.. :)
      【解决方案9】:

      冒着被否决的风险,我什至不会打扰 - 显然 PHP 希望您在逻辑上将 NULL 和 Undef 视为相同。我只是用它跑了——我创建了一个函数:

      bool isEmpty(& $davar);
      

      检查 isset(处理 null 和 undef)、"" 和 array()。请注意,这是故意不处理虚假;只是空的。 & 'reference-izer' 允许在未定义的情况下传递变量而没有错误消息,如果您首先检查 isset 并返回 false,则可以在没有错误的情况下对 "" 和 array() 进行下一次检查。

      下一个函数利用了这个函数,用在你会用到的地方

      $davar || some-default.
      

      那就是:

      mixed defaultForEmpty(& $daVar, $default);
      

      只有条件:

      if (isEmpty($daVar)) 
          return $default;
      else
          return $daVar;
      

      顺便说一句,这些适用于对象引用、数组索引、$_GET、$_POST 等。

      【讨论】:

        【解决方案10】:

        就我而言,我有以下代码:

        class SomeClass {
        
          private $cachedInstance;
        
          public instance()
          {
            if (! isset($this->cachedInstance)) {
              $this->cachedInstance = GetCachedInstanceFromDb(); // long operation, that could return Null if the record not found
            }
        
            return $this->cachedInstance;
          }
        }
        

        如果GetCachedInstanceFromDb() 返回null,它就会被多次调用。这一切都是因为isset() 会返回 false,即使该属性被显式设置为 Null。

        所以,我必须进行以下更改:

        1. 声明属性初始值为False;

        2. 检查当前变量值时使用严格(类型安全)比较;

        class SomeClass {
        
          private $cachedInstance = false; // #1
        
          public instance()
          {
            if ($this->cachedInstance === false) { // #2
              $this->cachedInstance = GetCachedInstanceFromDb();
            }
        
            return $this->cachedInstance;
          }
        }
        

        【讨论】:

          【解决方案11】:

          is_null($bar) 返回 true,因为它根本没有值。或者,您可以使用:

          if(isset($bar) && is_null($bar)) // returns false
          

          检查$bar 是否已定义并且仅在以下情况下返回true:

          $bar = null;
          if(isset($bar) && is_null($bar)) // returns true
          

          【讨论】:

          • 不,他说if(isset($bar))$bar = null 时给出false。
          • 这不会传递除 null 之外的任何其他变量(例如,如果 $bar = "test")。
          • 当 $bar = null isset() 将返回“false”并且 is_null() 将返回 true。假和真总是假的。
          • 这个答案是完全错误的。正如 OP 所说,isset($bar) 返回 false,即使在 $bar = null; 之后也是如此。
          猜你喜欢
          • 2021-01-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-23
          • 1970-01-01
          • 2014-03-24
          • 2014-07-16
          • 1970-01-01
          相关资源
          最近更新 更多