在PHP中如何从类外部调用受保护的方法

8

我有一个非常特殊的情况,需要从类外部调用受保护的方法。虽然我在编程方面非常谨慎,但在这个特殊情况下,我不完全反对这样做。在所有其他情况下,我需要继续禁止访问内部方法,因此我想保持该方法受保护。

有哪些优雅的方法可以在类外部访问受保护的方法?到目前为止,我发现了这个

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


最好的方法是什么?将函数更改为公共函数。 - Powerlord
6个回答

6

1
你应该将如何完成这件事作为答案告诉别人,而不是链接到其他答案(在这种情况下,文档)。但是,我们鼓励您链接到您的来源和其他重要的文档。 - Smar

4

我认为在这种情况下,重构代码以避免需要这样的方法可能是最优雅的方式。当然,一种选择是使用__call,并在其中解析debug_backtrace以查看调用该方法的类。然后检查好友白名单。

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();
    }
}

我想我需要洗个澡。

为什么不直接使用反射? - Smar

1

这有点笨拙,但可能是一个选项。

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

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

接着,在需要调用该函数的地方实例化一个Child的实例,而不是Parent


嗯,是的,在这种情况下这似乎是我的唯一选择。也许我应该把这个类叫做 Spy o_O。 - Chad Johnson

0

我只是随便提一下,因为我已经两年没有用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会更好地突出它)。


我试着使用反射来调用方法,但是PHP也不允许这样做。看起来你需要像其他帖子中建议的那样使用某种子类。如果你找到了一个可行的方法,开发人员可能会在未来将其归类为错误,并在升级到下一个版本时破坏你的代码。

我建议扩展这个类。


不错,这是个好主意。我可能会试一下。如果有效,我会告诉你的。 - Chad Johnson
我认为这只是创建了一个字符串 $obj->publicFunc,它是新函数的名称。当您尝试调用它时,作用域与普通函数相同。 - Tom Haigh
1
我无法让它工作:http://chadjohnson.ath.cx:8080/static/anonymous_function.phps。我得到的错误是“调用未定义的方法Chad::publicFunction()”。我可能做错了什么? - Chad Johnson
像@ChadJohnson一样,我遇到了“调用未定义的方法”的问题。看起来这个过程没有定义一个方法。浪费时间。使用反射代替。 - qris
1
@DaveL,你可以在方法上使用ReflectionMethod而不是ReflectionProperty来完成它。 - qris
显示剩余3条评论

0

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

曾经有这样的情况:

  • 你的类负责多个任务(实际上是两个或三个类包装在一起),或者
  • 封装规则被打破(例如实用函数)

通过找到任何绕过这些问题的方法,你离真正的解决方案还有很远的路要走。


2
一般来说,这是一个好建议。但有时候在定义范围之外调用方法是有充分理由的。例如,如果您不想将某个方法作为 API 的一部分,但又想在测试中调用它。或者在 CodeIgniter 视图中,您可能希望密码哈希函数不能从 Web 调用,但您确实希望在测试中调用它们。与 C++ 不同,PHP 没有“友元”类,可以访问类内部的特权。 - qris
1
如果您正在使用某些不公开方法的第三方API,但您确实需要访问该方法。Csaba提出了一个绝对正确的观点,但在非常罕见的情况下,您可能不得不打破规则。 - Chad Johnson

-3

假设您的方法声明如下:

protected function getTheFoo() {
    ...
}

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

使用方法:

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

这将绕过受保护的方法并直接访问实例变量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接