【问题标题】:calling __isset() magic method from empty() function, the magic method returns true but actually it should return false从 empty() 函数调用 __isset() 魔术方法,魔术方法返回 true 但实际上它应该返回 false
【发布时间】:2021-06-01 12:44:31
【问题描述】:
class Base
{
  private $firstName;
  private $lastName;

  function setName($firstName, $lastName){
    $this->firstName = $firstName;
    $this->lastName = $lastName;
  }

  function __isset($property){
    return empty($this->$property);
  }

}

$ob = new Base();
$ob->setName("Hello", "world");

if (empty($ob->firstName)) {
  echo "exist";
} else {
  echo "not exist";
}

// Output: exist

我不明白为什么输出是exist。

魔术方法返回true,但实际上它应该返回false,因为我已经设置了属性。

【问题讨论】:

  • 我想如果你设置了值,return empty($this->$property); 会返回 false,因为值不为空。
  • 是的,它应该返回 false,但它返回 true

标签: php oop magic-methods


【解决方案1】:

嗯。我不得不承认这也让我有点吃惊。

首先,让我们把重点放在一边:

  • 使用empty() 和isset() 可能很危险,而且不是一个好习惯。由于这些语言结构不是类型安全的,并且在需要时强制使用值,因此结果可能会导致意外错误。使用更具描述性和类型安全的选项通常更安全。将默认值设置为空字符串甚至null,并与之比较,等等。

  • 您问题中的代码看起来不太实用,我无法想象有很多这样的用例。通常情况下,使用魔法方法并不是一个好主意,而使用类型化属性和/或类型化访问器(get/set 方法)是一个好主意。我猜您正在尝试创建一个父类,您将在其中添加一些其他继承类将利用的魔术逻辑,这很好......但我并不特别喜欢。

  • 您的__isset() 实现存在固有缺陷,因为它在属性上调用empty()。想一想:当empty() 返回false(属性非为空)时,__isset() 也返回false。与您所期望的相反。修复很简单,只需返回相反的内容:return !empty($this->$property);。

但是,即使您应用该修复程序,您的代码也不会按预期工作。这就是我发现有点令人惊讶的一点......

问题是,是的,在不可访问的属性上调用 empty() 将调用魔术方法 __isset()(如果已定义)。

如果__isset() 返回false,empty() 返回真。如果__isset() 返回true,则检查__get() 的值是否为“假”(例如,空字符串、0、'0'、null、false 或空数组)全部返回true)。但如果魔法__get() 不存在,则该值无法访问,empty() 返回true。

因此,您还需要定义魔术访问器__get()。你的课程,“固定”,相当于like this:

class Base
{
  private $firstName;
  private $lastName;

  function setName($firstName, $lastName){
    $this->firstName = $firstName;
    $this->lastName = $lastName;
  }

  function __isset($property){
    return !empty($this->$property);
  }
  
  function __get($property) {
      return $this->$property;
  }

}

$ob = new Base();
$ob->setName("Hello", "world");

if(empty($ob->firstName)){
  echo "empty";
}
else{
  echo "not empty";
}

请注意,您需要两种方法。只定义魔法吸气剂也会失败,因为empty() 首先调用魔法__isset(),然后才(如果它返回true)魔法吸气剂。

【讨论】:

  • 不使用get方法能不能解决或者解释清楚..
  • 如答案中所述,您需要为您的工作方法定义 __get() 魔术方法。
  • 是的,我接受你的解决方案,但它是否有任何明确的解释为什么它的行为如此。
  • 我的回答中解释了:empty() 调用了__isset() 和__get()。之所以这样工作,是因为empty() 需要访问属性的值来进行比较,因为它将为多个不同的值(空字符串、null、未定义、false、0 等)返回true .为什么它会这样工作?因为它是这样设计的。
  • 但是如果没有声明变量,empty() 也会返回 true。
【解决方案2】:

查看您用于字段的访问修饰符,两者都设置为 private = 不能直接从类外部访问它,为此您将需要所谓的 getter -simple explanation:

class Base{
  private $firstName;
  private $lastName;

  function setName($firstName, $lastName){
    $this->firstName = $firstName;
    $this->lastName = $lastName;
  }
  
  function getFirstName (){
      return $this->firstName;
  }

  function getLastName (){
      return $this->lastName;
  }

  function __isset($property){
    return empty($this->$property);
  }

}

$ob = new Base();
$ob->setName("Hello", "world");

if(empty($ob->getFirstName())){
  echo "exist";
}
else{
  echo "not exist";
}

【讨论】:

  • 但是如果我们在类外用空函数调用私有属性,那么它会自动调用 __isset() 方法,该方法应该返回 false...
猜你喜欢
  • 1970-01-01
  • 2015-08-08
  • 1970-01-01
  • 2018-01-16
  • 1970-01-01
  • 2012-07-07
  • 2013-09-20
  • 1970-01-01
  • 2015-09-13
相关资源
最近更新 更多