Как добавить метод к существующему классу в PHP?
Я использую WordPress как CMS, и я хочу расширить один из его классов, не наследуя от другого класса; т.е. я просто хочу "добавить" к этому классу больше методов:
class A {
function do_a() {
echo 'a';
}
}
то
function insert_this_function_into_class_A() {
echo 'b';
}
(некоторый способ вставки последнего в класс A)
и
A::insert_this_function_into_class_A(); # b
Это возможно даже в цепком PHP?
Ответы
Ответ 1
Если вам нужен только доступ к Public API этого класса, вы можете использовать Decorator:
class SomeClassDecorator
{
protected $_instance;
public function myMethod() {
return strtoupper( $this->_instance->someMethod() );
}
public function __construct(SomeClass $instance) {
$this->_instance = $instance;
}
public function __call($method, $args) {
return call_user_func_array(array($this->_instance, $method), $args);
}
public function __get($key) {
return $this->_instance->$key;
}
public function __set($key, $val) {
return $this->_instance->$key = $val;
}
// can implement additional (magic) methods here ...
}
Затем завершите экземпляр SomeClass:
$decorator = new SomeClassDecorator(new SomeClass);
$decorator->foo = 'bar'; // sets $foo in SomeClass instance
echo $decorator->foo; // returns 'bar'
echo $decorator->someMethod(); // forwards call to SomeClass instance
echo $decorator->myMethod(); // calls my custom methods in Decorator
Если вам нужен доступ к API protected
, вам нужно использовать наследование. Если вам нужно получить доступ к API private
, вам необходимо изменить файлы классов. В то время как подход наследования прекрасен, модификация файлов классов может вызвать у вас проблемы при обновлении (вы потеряете любые исправления). Но оба варианта более эффективны, чем использование runkit.
Ответ 2
Обновленный способ для 2014 года, который справляется с областью.
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
Например:
class stdObject {
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
}
$obj = new stdObject();
$obj->test = function() {
echo "<pre>" . print_r($this, true) . "</pre>";
};
$obj->test();
Ответ 3
Вы можете использовать расширение runkit для этого, но вы должны действительно рассматривать регулярное наследование вместо этого.
См. runkit_method_add
.
Ответ 4
Если рассматриваемый класс реализует магию __call, то это возможно и довольно легко. Если вы хотите знать, как это работает, я предлагаю вам прочитать Расширение объектов новыми методами во время выполнения.
Ответ 5
Нет, вы не можете динамически изменять класс во время выполнения в PHP.
Вы можете выполнить это путем расширения класса с использованием регулярного наследования:
class Fancy extends NotSoFancy
{
public function whatMakesItFancy() //can also be private/protected of course
{
//
}
}
Или вы можете редактировать исходные файлы Wordpress.
Я предпочел бы путь наследования. В долгосрочной перспективе это намного проще.