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

Posted

技术标签:

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

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

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

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

【问题讨论】:

最好的方法是什么?将函数更改为公开。 【参考方案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');

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

【讨论】:

以上是关于从 PHP 中的类外部调用受保护的方法的主要内容,如果未能解决你的问题,请参考以下文章

我可以/如何...在 PHP 中的类之外调用受保护的函数

如何从 Ruby 中的实例方法访问受保护的类方法?

从 PHP 中的类外部调用私有方法和私有属性

从不同包的另一个实例的子类调用受保护的方法

在 Java 中,为啥可以从同一个包中的类外部访问受保护的成员? [复制]

如何从 Derived 内部调用 Base 实例中的受保护成员函数?