【问题标题】:__call catches static method calls__call 捕获静态方法调用
【发布时间】:2025-12-04 03:30:02
【问题描述】:

我同时使用魔术方法_call_callStatic 来实现我自己的ORM/Activerow 之类的东西。它们主要用于捕获某些函数调用:__call 负责 getter 和 setter,__callStatic 负责 findBy 方法(例如 findById)。

为了映射外键,我正在尝试将调用转换为例如getArticle 返回 Article::findById() 的值。为此,我在__call 中使用了这个案例:

if (strstr($property, "_id")) {  
 return $foreignClass::findById($this->getId()); 
}

其中$property__callsetget 之后的子字符串,$foreignClass 是字符串的其余部分。因此,在调用 getArticle 的情况下,$property 将是 get,$foreignClass 将是 Article

我放置了一些回声以确保值正确。然而,我的__call 方法被调用而不是我的__callStatic。如果我创建一个隐式静态方法findById,它会被调用(因此它确实将其识别为静态调用)。如果我专门打电话给Article::findById()__call 也会接听。

这是相对较新的__callStatic 的错误,还是我做错了什么?

编辑: 问题似乎出在这部分:

_call() 在对象上下文中调用不可访问的方法时被触发。
在静态上下文中调用不可访问的方法时会触发 __callStatic()。

虽然我是在一个类上调用它,但我是从一个对象上下文中调用它。在这种情况下有没有办法进入静态上下文?

【问题讨论】:

  • 我有一种可怕的感觉,这里缺少重要的信息。魔术方法定义在哪些类中?他们被称为哪个类?前面提到的类是同一继承树的成员吗?如果有,他们的关系是什么?
  • 这里的继承树是DBObject(我在这里展示了代码)->Article->Activity。文章和活动没有覆盖相关代码,所有这些逻辑都发生在 DBObject 中。我现在已将代码更改为使用 __get 和 __set 而不是 __call,而且现在似乎可以正确触发 __callStatic。
  • 所以$foreignClassArticle 并且在Activity 的上下文中调用该方法。这使得Article 成为祖先类。问题来了。
  • $foreignClass 在这种情况下确实是 Article 。变量指的是外键所指的表/对象。在这种情况下,Activity 指向的是 Article,但它也可能是指向 Article 的 Comment(Comment 也是 DBObject 的子类)。计划是在这里实现类所称的唯一真正的区别;它使用该名称插入到正确的表中。既然 Article 和 Activity 都没有覆盖魔法方法,那么它们的行为不应该和 DBObject 一样吗?

标签: php activerecord orm getter-setter


【解决方案1】:

由于您提供的代码在Activity 对象的上下文中运行,并且由于$foreignClas 的值是Article,它是Activity 的祖先,PHP 假定您打算使用to call an ancestor's implementation方法。

要脱离对象上下文,AFAIK 除了这种绝对可怕的技术别无选择:

$id = $this->getById();
return call_user_func(
    function() use($foreignClass, $id) { 
        return call_user_func("$foreignClass::findById", $id);
    }
);

【讨论】:

  • 嗯,这很有趣。我之前读过它,但不知何故又回到假设 :: 只是调用静态方法。我会进一步研究这个,但这至少是 :: 实际所做的一个很好的来源:)
【解决方案2】:

__callStatic 魔术方法仅在 PHP 5.3 中引入。在此之前,我相信静态调用是通过__call 路由的,就像普通的方法调用一样。我的猜测是您使用的是 php -v在命令行的输出是什么?

【讨论】:

  • 我刚刚升级到 5.4 可以使用 __callStatic...我会测试一下,看看它是否能正常工作。
最近更新 更多