Даны следующие классы с классом 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
от B::privateMethod
потому что последний не виден A::test
как объяснили Вот.
Как еще можно изменить поведение этого метода частной библиотеки самым чистым способом (например, без дублирования кода путем копирования всего класса и его изменения)?
Вы можете манипулировать поведением косвенно. Это фрагмент, который вас интересует.
$allCss = $this->css;
if ($this->isStyleBlocksParsingEnabled) {
$allCss .= $this->getCssFromAllStyleNodes($xpath);
}
Глядя на установщиков классов, вы можете позвонить disableStyleBlocksParsing
чтобы предотвратить вызов функции.
$allCss
переменная берется прямо из $this->css
, который изменяется только setCss
метод.
Итак, у вас есть два варианта:
isStyleBlocksParsingEnabled
ложный и неизменный, затем переопределить 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
почти все мои были бы частными методами.
Это потому private
находится только в сфере действия самого класса. Я тебя использовал protected
вы бы переопределили функцию, потому что protected
Метод означает, что он доступен для дочерних классов.
Вы можете изменить доступность метода класса, используя ReflectionMethod::setAccessible()
:
$myEmogrifier = new \Pelago\Emogrifier;
$reflectedMethod = new ReflectionMethod($myEmogrifier, 'getCssFromAllStyleNodes');
$reflectedMethod->setAccessible(true);
$argument = new \DOMXpath(new \DOMDocument);
$returnValue = $reflectedMethod->invoke($myEmogrifier, $argument);
Примите во внимание, что этот код будет «хрупким», поскольку автор библиотеки не будет учитывать, что пользователь библиотеки полагается на результат частной функции. Может быть, лучше просто продублировать код функции самостоятельно, чем возиться с самой библиотекой.
Вы можете изменить жесткий код visibility
собственности через ReflectionClass :: setAccessible
это часть ReflectionClass.
Устанавливает свойство, которое будет доступно. Например, это может позволить
и частные свойства, которые будут доступны.
Это опасно но в некоторых случаях вы можете использовать его.