23

我将 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 中是否可行?

4

5 回答 5

28

如果只需要访问类的 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

如果您需要访问protectedAPI,则必须使用继承。如果需要访问privateAPI,则必须修改类文件。虽然继承方法很好,但修改类文件可能会在更新时给您带来麻烦(您将丢失所做的任何补丁)。但两者都比使用 runkit 更可行。

于 2010-06-10T07:20:47.263 回答
10

应对范围的 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();
于 2014-08-13T12:23:26.033 回答
3

您可以为此使用runkit 扩展,但您应该真正考虑常规继承。

runkit_method_add

于 2010-06-10T05:49:36.060 回答
3

如果有问题的类实现了 __call 魔法,那么它是可能的,而且非常容易。如果您想知道这是如何工作的,我建议您阅读在运行时使用新方法扩展对象

于 2010-06-10T06:18:58.763 回答
-3

不,您不能在 PHP 运行时动态更改类。

您可以通过使用常规继承扩展类来完成此操作:

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

或者您可以编辑 Wordpress 源文件。

我更喜欢继承方式。从长远来看,它更容易处理。

于 2010-06-10T06:24:33.920 回答