如何向 PHP 中的现有类添加方法?

发布于 2024-09-05 05:30:22 字数 388 浏览 5 评论 0原文

我使用 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 中是否可能?

I'm using WordPress as a CMS, and I want to extend one of its classes without having to inherit from another class; i.e. I simply want to "add" more methods to that class:

class A {

    function do_a() {
       echo 'a';
    }
}

then:

function insert_this_function_into_class_A() {
    echo 'b';
}

(some way of inserting the latter into A class)

and:

A::insert_this_function_into_class_A();  # b

Is this even possible in tenacious PHP?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

和我恋爱吧 2024-09-12 05:30:22

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

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

If you only need to access the Public API of the class, you can use a 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 ...
}

Then wrap the instance of 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

If you need to have access to the protected API, you have to use inheritance. If you need to access the private API, you have to modify the class files. While the inheritance approach is fine, modifiying the class files might get you into trouble when updating (you will lose any patches made). But both is more feasible than using runkit.

£冰雨忧蓝° 2024-09-12 05:30:22

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();

An updated way for 2014 that copes with scope.

public function __call($method, $arguments) {
    return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}

Eg:

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();
别在捏我脸啦 2024-09-12 05:30:22

您可以使用 runkit 扩展 来实现此目的,但您应该真正考虑常规继承反而。

请参阅 runkit_method_add

You can use the runkit extension for this, but you should really consider regular inheritance instead.

See runkit_method_add.

对你而言 2024-09-12 05:30:22

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

您可以通过使用常规继承来扩展类来实现此目的:

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

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

我更喜欢继承方式。从长远来看,处理起来要容易得多。

No you can't dynamically change a class during runtime in PHP.

You can accomplish this by either extending the class using regular inheritance:

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

Or you could edit the Wordpress source files.

I'd prefer the inheritance way. It's a lot easier to handle in the long run.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文