web-dev-qa-db-ja.com

PHPの既存のクラスにメソッドを追加するにはどうすればよいですか?

WordPressをCMSとして使用しており、別のクラスから継承せずにそのクラスの1つを拡張したい、つまり、そのクラスにメソッドを「追加」したいだけです。

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でも可能ですか?

18
Gal

クラスのパブリックAPIにアクセスするだけでよい場合は、 デコレータ を使用できます。

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 AP​​Iにアクセスする必要がある場合は、継承を使用する必要があります。 private AP​​Iにアクセスする必要がある場合は、クラスファイルを変更する必要があります。継承アプローチは問題ありませんが、クラスファイルを変更すると、更新時に問題が発生する可能性があります(作成されたパッチはすべて失われます)。ただし、どちらもrunkitを使用するよりも実行可能です。

21
Gordon

スコープに対応する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();
7
Chris

これには runkit拡張 を使用できますが、代わりに通常の継承を検討する必要があります。

見る - runkit_method_add

3
Artefacto

問題のクラスが__callマジックを実装している場合、それは可能であり、非常に簡単です。これがどのように機能するかを知りたい場合は、 実行時に新しいメソッドでオブジェクトを拡張する を読むことをお勧めします。

2
wimvds