__call 等效于公共方法

Posted

技术标签:

【中文标题】__call 等效于公共方法【英文标题】:__call equivalent for public methods 【发布时间】:2011-10-04 20:28:36 【问题描述】:

我有一个用于与我的网络应用程序交互的 API,由一个类定义。每个可公开访问的方法都需要在运行之前完成身份验证。我不想在每个方法中一遍又一遍地放置同一行,我想使用神奇的 __call 函数。但是,它只适用于私有或受保护的方法,而我的方法需要公开才能与 Zend_Json_Server 一起使用。

class MY_Api

  public function __call($name, $arguments)
  
    //code here that checks arguments for valid auth token and returns an error if false
  

  public function myFunction($param1, $param2, $param3)
  
    //do stuff when the user calls the myFunction and passes the parameters
    //this function must remain public so that Zend_Json_Server can parse it
    //but I want it intercepted by a magic method so that the authentication
    //can be checked and the system bails before it even gets to this function.
  

是否可以挂钩这些公共函数并可能在它们被调用之前取消它们的执行?

【问题讨论】:

还没有。我不确定它是否适合用于应用程序的这一部分。这是一个休息 API,所以他们不是登录和设置会话,而是传递一个令牌。 什么是调用公共方法,调用者可以调用认证方法吗? @webbiedave 调用者是 Zend_Json_Server->handle() 方法,所以我必须扩展 Zend_Json_Server 类,这样做似乎有点过头了。 【参考方案1】:

__call 实际上适用于所有方法,包括公共方法。但是,如果公共方法已经存在,它将无法工作的原因是因为您的类之外的代码已经可以访问公共成员。 __call 仅对调用代码无法访问的成员调用。

据我所知,除了使用某种装饰器模式外,实际上没有其他选择可以满足您的需求:

class AuthDecorator 
    private $object;

    public function __construct($object) 
        $this->object = $object;
    

    public function __call($method, $params) 
        //Put code for access checking here

        if($accessOk) 
            return call_user_func_array(array($this->object, $method), $params);
        
    


$api = new MY_Api();
$decoratedApi = new AuthDecorator($api);

//any calls to decoratedApi would get an auth check, and if ok, 
//go to the normal api class' function

【讨论】:

这里的解决方案是使用代理的经典面向方面编程,这正是您所需要的。我会狡辩说,因为 __call() 仅在方法不可访问并且所有公共方法都可以访问时才被调用,所以 __call() 可以被认为不适用于公共方法。你让我兴奋地认为我可能错过了一个漏洞,但事实并非如此。 :( 或重命名所有函数以在名称中添加_ 左右。你可以调用方法x,它会经过__call,然后会调用公共方法x_。现在我想起来,装饰器可能更容易。 :) @David Harkness 啊,谢谢 - 方面正是我要提到的另一件事,但我只能想到特征 :) 但是,是的,从这个角度来看,你对 __call 是完全正确的。 我喜欢这个想法,但我认为 Zend_Json_Server 可能会妨碍我的可行性,因为它使用反射来确定哪些方法是可访问的。我认为将装饰器包裹在我的班级周围会掩盖可用的方法。 @webbiedave 建议查找一个级别,所以也许我会检查 $zendjsonserver->handle() 调用并在它进入课堂之前将其扼杀在萌芽状态。这不是最好的方法,但是 zend_json_server 的反射部分并没有给我很多选择。 我给了这个答案,因为在大多数情况下它是正确的答案。因为我需要用我的函数传递 Zend_Rest_Server 类以便它可以进行反射,所以它对我不起作用。我最终将身份验证代码向上移动到控制器中,以便它在调用 handle() 方法之前进行检查,从而解决了问题。【参考方案2】:

由于您将我的评论作为可能的解决方案,我已将其格式化为后代的答案:

如果面向方面或装饰器的解决方案不适合您,您可以尝试更基于框架的解决方案,方法是将检查身份验证的代码放在公共方法的调用者中,甚至更高。

【讨论】:

我之前没用过Zend_Json_Server,但是它的亲亲表亲Zend_Controller_Action定义了preDispatch(),它在实际操作方法之前被调用。也许 JSON 组件提供了这样的功能。 好主意,@David,但 Zend_Json_Server 没有,它扩展了 Zend_Server_Abstract,它也没有。 感谢您将其作为@webbiedave 的答案。这确实最终解决了这个特殊案例的问题。

以上是关于__call 等效于公共方法的主要内容,如果未能解决你的问题,请参考以下文章

如果设置类的公共属性,您是不是对 __init__ 方法进行单元测试?

Elixir/Erlang 中的命名函数是不是有等效于 __MODULE__ 的方法?

在 JavaScript 中的公共方法中获取私有方法值

动态规划_基础_最长公共子序列_多种方法_递归/dp

C# 等效于 VB.NET 接口实现

Javascript进阶---编写类