Как добавить метод к существующему классу в 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.

Ответ 5

Нет, вы не можете динамически изменять класс во время выполнения в PHP.

Вы можете выполнить это путем расширения класса с использованием регулярного наследования:

class Fancy extends NotSoFancy
{
    public function whatMakesItFancy() //can also be private/protected of course
    {
        //    
    }
}

Или вы можете редактировать исходные файлы Wordpress.

Я предпочел бы путь наследования. В долгосрочной перспективе это намного проще.