PHP检查对象或类中是否存在属性

236

我知道PHP没有纯粹的对象变量,但我想检查给定对象或类中是否存在某个属性。

$ob = (object) array('a' => 1, 'b' => 12); 
或者
$ob = new stdClass;
$ob->a = 1;
$ob->b = 2;

JS中,我可以编写以下代码来检查变量a是否存在于一个对象中:

if ('a' in ob)

PHP中,是否可以像这样做?


4
提一下,当我们进行面向对象编程时,我们使用属性而不是变量这个术语,就像我们用方法而不是函数一样。 - Christopher Bonitz
10个回答

404

19
如果属性存在但未被定义,isset()函数将返回false。 - user1959825
1
isset() 可以与 empty() 结合使用来检查属性和值。 - user5890979
4
如果您了解其注意事项,使用isset()速度要比property_exists()快得多,尽管isset()的答案是错误的。 - Nico Westerdale
这是一个使用empty()更好的情况吗?!empty($var) ? - b_dubb
2
@b_dubb 不,空数组、0、false、null、'' 都会通过 empty() 返回 true。 - Peter
显示剩余2条评论

78

要检查属性是否存在且是否为null,您可以使用函数property_exists()

文档:http://php.net/manual/en/function.property-exists.php

与isset()相反,property_exists()即使属性的值为NULL也会返回TRUE。

bool property_exists ( mixed $class , string $property )

示例:

if (property_exists($testObject, $property)) {
    //do something
}

10
因为它非常准确地回答了明确的问题,所以应将此回答标记为被接受的答案。isset不适用于测试对象属性的存在。 - Christopher Bonitz
然而,property_exists在属性已声明但未定义时返回true(实际上,属性尚不存在)。 - undefined

20

issetproperty_exists都不能满足我的需求。

  • isset会在属性存在但为NULL的情况下返回false。
  • property_exists会在属性属于对象类定义时返回true,即使它已被取消设置。

最终我选择了:

    $exists = array_key_exists($property, get_object_vars($obj));

例子:

    class Foo {
        public $bar;

        function __construct() {
            $property = 'bar';

            isset($this->$property); // FALSE
            property_exists($this, $property); // TRUE
            array_key_exists($property, get_object_vars($this)); // TRUE

            unset($this->$property);

            isset($this->$property); // FALSE
            property_exists($this, $property); // TRUE
            array_key_exists($property, get_object_vars($this)); // FALSE

            $this->$property = 'baz';

            isset($this->$property); // TRUE
            property_exists($this, $property); // TRUE
            array_key_exists($property, get_object_vars($this));  // TRUE
        }
    }

property_exist + unset property 可能导致错误行为。这似乎是最安全的方法。 - Thanh Trung
1
array_key_exists() 在 php 7.4 中已被弃用。 - Ali_Hr
“Using array_key_exists() on objects is deprecated” 中的关键词是 objects。get_object_vars() 返回一个数组,所以我们仍然可以使用它。 - smariot
@Ali_Hr 不知道你在文档中看到了什么。 array_key_exists在PHP 7.4中并没有被弃用。 - Alexander Behling
1
为什么要取消类属性? property_exists的工作方式如预期所示。 如果您取消了类属性,则其内部设置为null。 根据文档,如果属性为null,则property_exists也会返回true。 因此,我对您的期望感到困惑。 还值得一提的是,如果实现了神奇方法__get,则property_exist将无法正常工作。 - Alexander Behling

18

解决方案

echo $person->middleName ?? 'Person does not have a middle name';

为了更清楚地展示这个语句在if语句中的样子,以便更好地理解它是如何工作的。

if($person->middleName ?? false) {
    echo $person->middleName;
} else {
    echo 'Person does not have a middle name';
}

说明

传统的PHP检查某个东西是否存在的方法是这样做:

if(isset($person->middleName)) {
    echo $person->middleName;
} else {
    echo 'Person does not have a middle name';
}

或者更加特定于类的方式:

if(property_exists($person, 'middleName')) {
    echo $person->middleName;
} else {
    echo 'Person does not have a middle name';
}

这些语句在长表达式中都可以使用,但在三元语句中会变得不必要得繁琐,如下所示:

isset($person->middleName) ? echo $person->middleName : echo 'Person does not have a middle name';

您也可以只使用三元运算符来实现:

echo $person->middleName ?: 'Person does not have a middle name';

但是......如果该值不存在(未设置),它将引发一个E_NOTICE错误,并且不是最佳实践。如果该值为null,它将不会引发异常。

因此,三元运算符挺身而出,使这成为一个简洁的答案:

echo $person->middleName ?? 'Person does not have a middle name';


"Elvis operator"(?:)并不检查属性是否存在!而 ?? 是空值合并运算符。 - mickmackusa
@mickmackusa 如果您实际上阅读了我的描述,您会看到我提到了关于 ?: 的内容。 - Rob
我想我不认为有必要在这个页面上提到?:,因为标题明确说明:PHP检查对象或类中是否存在属性 - mickmackusa

4

如果您想知道您定义的类的实例中是否存在某个属性,只需将property_exists()isset()结合使用即可。

public function hasProperty($property)
{
    return property_exists($this, $property) && isset($this->$property);
}

2
调用property_exists($this, $property)在这里有点多余,因为你的代码结果始终与仅使用isset($this->$property)相同。 - MarthyM
这是更全面的事实检查,因为isset()无法告诉您属性是否是类定义的真正成员。稍后我会再次查阅以确保。 - Anthony Rutledge
没错,对于实际的类属性,输出将会是相同的。但如果你有使用了 __get() 和更重要的 __isset() 魔术方法的虚拟属性,则在某些情况下输出将会不同。 - MarthyM

3
要检查某个东西是否存在,您可以使用 PHP 函数 isset() 请参阅 php.net。此函数将检查变量是否已设置且不为 NULL。
示例:
if(isset($obj->a))
{ 
  //do something
}

如果您需要检查类中是否存在属性,则可以使用内置函数property_exists()
例如:
if (property_exists('class', $property)) {
    //do something
}

3

这是比较新的技术,所以请确保你正在运行 PHP 8 版本:

$ob?->a

Reference link


2
它不会检查属性是否存在。 - Saleh Hashemi

3
通常我使用一种自定义助手。
    /**
     * @param Object $object
     * @param string $property as a string with nested properties 'prop1.nesterdProp.deepvalue'
     * @param mixed $default
     * @return mixed
     */
    function getPropertyOrDefault(Object $object, string $property, $default = null)
    {
        $value = $object;
        $path = explode('.', $property);
        foreach ($path as $prop) {
            if (is_object($value) && property_exists($value, $prop)) {
                $value = $value->{$prop};
            } else {
                return $default;
            }
        }
        return $value;
    }

请记住,如果属性为空,则会得到空值并且没有默认值。

顺便说一下,类似的帮助程序也适用于JS。


2

在php 7.4中,使用array_key_exists()来操作对象已经被弃用。

相反,应该使用isset()或property_exists()。

参考:php.net


0

我在这里发表一下我的看法。

给定以下类:

class Foo
{
  private $data;

  public function __construct(array $data)
  {
    $this->data = $data;
  }

  public function __get($name)
  {
    return $data[$name];
  }

  public function __isset($name)
  {
    return array_key_exists($name, $this->data);
  }
}

接下来会发生以下事情:

$foo = new Foo(['key' => 'value', 'bar' => null]);

var_dump(property_exists($foo, 'key'));  // false
var_dump(isset($foo->key));  // true
var_dump(property_exists($foo, 'bar'));  // false
var_dump(isset($foo->bar));  // true, although $data['bar'] == null

希望这能帮助到任何人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接