【问题标题】:Call a protected method from outside a class in PHP从 PHP 中的类外部调用受保护的方法
【发布时间】:2010-11-02 05:20:50
【问题描述】:

我有一个非常特殊的情况,我需要从类外部调用受保护的方法。我非常清楚我在编程方面所做的事情,但在我遇到的这种特殊情况下,我不会完全反对这样做。在所有其他情况下,我需要继续禁止访问内部方法,因此我希望保持该方法受到保护。

有哪些优雅的方法可以访问类之外的受保护方法?到目前为止,我已经找到了this

我想有可能创建某种目标类的双重代理实例,偷偷地提供对内部的访问......

【问题讨论】:

  • 最好的方法是什么?将函数更改为公开。

标签: php access-modifiers


【解决方案1】:

在 PHP 中,您可以使用反射来做到这一点。 要调用受保护或私有方法,请使用 setAccessible() 方法 http://php.net/reflectionmethod.setaccessible(只需将其设置为 TRUE)

【讨论】:

  • 您应该告诉如何做这件事作为答案,而不是链接其他答案(在这种情况下,文档)。不过,我们鼓励您链接到您的源代码和其他重要的文档。
【解决方案2】:

我认为在这种情况下,重构以使您不需要这种事情可能是最优雅的方式。说一种选择是使用__call 并在该解析debug_backtrace 中查看哪个类调用了该方法。然后检查一个朋友whitelst

class ProtectedClass {

    // Friend list
    private $friends = array('secret' => array('FriendClass')); 

    protected function secret($arg1, $arg2) {
        // ...
    }

    public function __call($method, $args) {

        $trace = debug_backtrace();
        $class = $trace[1]['class'];
        if(in_array($class, $this->friends[$method]))
            return $this->$method($args[0], $args[1]);

        throw new Exception();
    }
}

我想我需要洗个澡。

【讨论】:

  • 为什么不直接使用反射?
【解决方案3】:

这有点笨拙,但可能是一种选择。

添加一个子类以访问受保护的函数

public class Child extends Parent {
    public function protectedFunc() {
        return parent::protectedFunc();
    }
}

然后,实例化Child 的实例,而不是您需要调用该函数的Parent

【讨论】:

  • 嗯,是的,这看起来是我目前唯一的选择。也许我应该称这个类为 Spy o_O。
【解决方案4】:

我只是把它扔在那里,因为我已经两年没有用 PHP 编程了。你能像这样在调用受保护方法的类中添加一个函数吗?

$obj->publicFunc = create_function('$arg', 'return $this->protectedFunc($arg);');

编辑我认为 Tom 在查看 create_function 的文档时是正确的。当您尝试使用此示例调用 $this 时,它的范围似乎是“错误的”。


看起来自 PHP 5.3.0 起也支持传统的匿名函数(我的第一个解决方案可能不起作用),所以我可能会这样写:

$obj->publicFunc = function($arg) { 
     return $this->protectedFunc($arg); 
};

因为我认为它看起来更干净一些(当然,您选择的 IDE 会更好地突出它)。


呃,我尝试使用 Reflection 调用该方法,但 PHP 也不允许您这样做。似乎您将不得不像其他海报所建议的那样使用某种子类。如果您找到一种可行的方法,开发人员可能会将其归类为错误,并在您升级到下一个版本时破坏您的代码。

我建议扩展课程。

【讨论】:

  • 诺诺,拍得不错。我可能会试一试。如果有效,我会通知您。
  • 我认为这只会创建一个字符串 $obj->publicFunc ,它是新函数的名称。当您尝试调用它时,范围与普通函数一样。
  • 我无法正常工作:chadjohnson.ath.cx:8080/static/anonymous_function.phps。我得到的错误是“调用未定义的方法 Chad::publicFunction()”。我可能做错了什么?
  • 反射是个好主意,在 5.3 中您可以使用 setAccessible() 让您调用受保护的方法
  • @DaveL,你可以在方法上做到这一点,使用 ReflectionMethod 而不是 ReflectionProperty。
【解决方案5】:

如果我必须调用私有函数,我会考虑程序设计有什么问题?

以前是这样的

  • 您的班级负责几件事(实际上是两个或三个班级包装在一起)或
  • 封装规则被破坏(例如实用程序函数)

通过找到任何方法来解决这些问题,您将离真正的解决方案更近一步。

【讨论】:

  • 一般来说这是个好建议。但有时在定义范围之外调用方法是有充分理由的。例如,如果您不想让某个方法成为 API 的一部分,但您想在测试中调用它。或者在 CodeIgniter 视图中,您可能希望您的密码哈希函数不能从 Web 调用,但您确实希望在测试中调用它们。与 C++ 不同,PHP 没有对类内部具有特权访问权限的“朋友”类。
  • 另外,如果您正在使用一些不公开该方法的第三方 API,但您确实需要访问该方法。 Csaba 提出的观点绝对正确,但在极少数情况下,您可能不得不违反规则。
【解决方案6】:

假设你的方法声明是这样的:

protected function getTheFoo() {
    ...
}

protected function setTheFoo($val) {
    ...
}

用法:

$obj->__get('the_foo');
$obj->__set('the_foo', 'myBar');

这会绕过受保护的方法,直接进入实例变量。

【讨论】:

    猜你喜欢
    • 2012-08-28
    • 2012-06-23
    • 2012-11-25
    • 2018-06-30
    • 2013-09-27
    • 2015-12-08
    • 2011-05-18
    • 2016-02-19
    • 1970-01-01
    相关资源
    最近更新 更多