如何从库类中重写私有方法

时间:2015-05-21 14:52:44

标签: php override private

鉴于以下类main来自external library,因此我无法更改它:

A

这会导致class A { public function test () { $this->privateMethod(); } private function privateMethod () { echo('A'); } } class B extends A { private function privateMethod () { echo('B'); } } $b = new B(); $b->test(); A打印出来A::privateMethod而不是来自B的{​​{1}},因为后者对B::privateMethod不可见,如所解释的那样A::test 3}}

我怎样才能以最干净的方式修改这个私有库方法的行为(例如,没有复制整个类并更改它的代码重复)?

4 个答案:

答案 0 :(得分:4)

这是因为private仅在类本身的范围内。我使用了protected你会覆盖这个函数,因为protected方法意味着它可用于子类。

答案 1 :(得分:1)

您可以使用ReflectionMethod::setAccessible()更改类方法的辅助功能:

$myEmogrifier = new \Pelago\Emogrifier;
$reflectedMethod = new ReflectionMethod($myEmogrifier, 'getCssFromAllStyleNodes');
$reflectedMethod->setAccessible(true);
$argument = new \DOMXpath(new \DOMDocument);
$returnValue = $reflectedMethod->invoke($myEmogrifier, $argument);

考虑到此代码将是“脆弱的”,因为库的作者不会考虑库的用户依赖于私有函数的结果。简单地复制函数代码可能比弄乱库本身更好。

答案 2 :(得分:1)

您可以间接操纵行为。这是您感兴趣的片段。

$allCss = $this->css;

if ($this->isStyleBlocksParsingEnabled) {
    $allCss .= $this->getCssFromAllStyleNodes($xpath);
}

查看类设置器,可以调用disableStyleBlocksParsing来阻止调用该函数。

$allCss变量直接来自$this->css,只能通过setCss方法进行修改。

所以你有两个选择:

  • 扩展该类,使isStyleBlocksParsingEnabled为false且不可变,然后覆盖setCss方法以执行您希望getCssFromAllStyleNodes执行的操作。
  • 致电disableStyleBlocksParsing,然后使用预处理文字致电setCss

以下是第一个选项的示例:

class MyEmogrifier extends Emogrifier
{
    public function __construct($html = '', $css = '')
    {
        parent::__construct($html, $css);

        $this->disableStyleBlocksParsing();
    }

    public function setCss($css)
    {
        // Preprocess CSS here.

        parent::setCss($css);
    }
}

所以没有霰弹枪手术或需要反射。

说实话。我觉得甚至不太喜欢使用像这样具体的图书馆。我使用protected几乎所有的私有方法。

答案 3 :(得分:0)

您可以通过ReflectionClass::setAccessible更改属性的硬编码visibility 这是ReflectionClass的一部分。

  

设置可访问的属性。例如,它可能允许受保护   和私人财产。

这很危险但在某些情况下你可以使用它。