从 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 中的类外部调用受保护的方法的主要内容,如果未能解决你的问题,请参考以下文章