【问题标题】:PHP Child class Magic __isset works but __get doesn'tPHP 子类 Magic __isset 有效,但 __get 无效
【发布时间】:2012-12-11 02:54:52
【问题描述】:

我有一个抽象父类Mongo_Document(来自mongodb-php-odm)和一个继承类Model_ActionPlanMongo_Document 具有神奇的 __isset 和 __get 方法,它们与 Mongo_Document 类中的数组进行交互。

我正在尝试使用以下代码(来自Model_ActionPlan 方法内部的sn-p):

if (isset($this->status))
{
    if (($this->status === "closed") AND ($this->close_type != "failure"))
    {
        return;
    }
}

(请注意,close_type 保证在 status == 'closed' 时被设置。)

isset 调用返回true,然后继续执行下一条语句。在那里,我收到以下错误:

 Undefined property: Model_ActionPlan::$status

但是,如果我将 $this->status 替换为 parent::__get('status'),此代码将按预期工作。请注意,程序中的其他任何地方,我都可以使用:

$ap = new Model_ActionPlan($plan_id);
echo $ap->status;
// Prints 'closed' (or 'active') as expected

只有在这里,在类本身内部,这不起作用。

我环顾四周,似乎找不到任何地方说不能在子类中调用魔术方法。我可以改用parent::__get 调用,但我认为这可能是错误的做法。有谁知道是否有正确/更好的方法来做到这一点?

2012 年 12 月 16 日更新 #1: 父类的完整代码是here on Github

2012 年 12 月 18 日更新 #2: 对于询问在何处或是否正确设置的人,答案是由于调用parent::__get('status') 确实 工作,问题显然不是变量没有设置。 __get() 正在从名为 _object 的私有实例变量中获取其数据。如果我var_dump($this),我看到$this->_object['status'] 确实 等于预期的“关闭”值。

更新 #3: 子类的代码可在https://gist.github.com/4332062 获得。 重要的部分从第 69 行开始。


我见过this similar question,但那是关于使用父母的魔法方法来获取孩子的属性,而我的问题是使用父母的getter来获取父母的属性。

【问题讨论】:

  • 您使用的是什么版本的 PHP?这不应该发生。
  • 请在 __get 和 __isset 重载的父类中添加更多代码。顺便说一下“AND”和“&&”的注意行为是不同的
  • @IgorVizma 我在 Github 上添加了一个指向父类源的链接。是的,我知道AND&& 的行为是不同的。这就是为什么里面有这么多括号。我们的代码风格指南说我们应该根据需要使用ANDOR 加上额外的括号,因为编写它的人认为这样更容易阅读。它们之间的唯一区别是优先级,而括号解决了这个问题。
  • 毫无意义。我复制了课程,并尝试复制它。没有出错。
  • 无法使用 5.4.9 和 5.4.10 重现。当您使用步进调试器 (Xdebug) 进行跟踪时,实际发生了什么

标签: php inheritance mongodb-php magic-methods


【解决方案1】:

父类中的 __get 函数有些复杂,所以我还没有完全弄清楚是否会发生以下情况。如果您的 __get 函数一旦被调用,就会以某种方式触发另一个调用回自身(可能对堆栈上的其他函数进行一些干预调用),这正是会发生的情况。

请参阅http://php.net/manual/en/language.oop5.overloading.php#55486,它显示了当 getter 触发对自身的调用时所记录的完全相同类型的错误。在那种情况下,它很容易被发现,但是对于像 func() 到 __get() 到 funcB() 到 funcC() 到 __get() 这样的更复杂的调用图,就不容易发现了。

【讨论】:

  • 你知道,你可能有一些东西。我将不得不检查是否发生了这种情况。我不认为__get 是在调用自己,但可能是某种其他类型的“调用自己”表现出相同的行为。
  • 不幸的是,我无法在赏金到期之前测试这是否正确。对不起。但是,我不得不说这几乎肯定是正确的答案。我删除了一行可能导致嵌套调用 __get 的代码并解决了问题。
【解决方案2】:

不确定我是否正确,但你不应该使用

$this->_object['status'] 

而不是

$this->status

【讨论】:

  • 如果魔术 getter 只获取数组元素,那将是正确的。但是,__get 方法在从数组中获取元素之前会执行一些操作。我需要使用--get 方法才能让它做这些事情。此外,如果存在这样的方法,我认为使用父类的内部而不是使用正确的访问方法是不好的做法。如果你使用$this->_object,然后父实现发生变化,你就不得不担心了。如果您使用记录在案的方法,那么您不会。
  • 可能更值得评论,因为这更像是一个问题而不是一个明确的答案。
猜你喜欢
  • 2020-01-25
  • 2021-02-21
  • 2013-12-23
  • 2023-04-02
  • 2019-09-18
  • 2013-07-28
  • 1970-01-01
  • 1970-01-01
  • 2022-11-04
相关资源
最近更新 更多