9

サルのパッチがどのように機能するか、およびそれを自分のオブジェクト/メソッドで機能させる方法を理解しようとしています。

私はこのライブラリを見てきましたが、それは私が自分でやりたいことを正確に行います: https://github.com/antecedent/patchwork

これを使用すると、オブジェクトからメソッドを再定義できます。そのために「モンキーパッチ」手法を使用します。しかし、ソースを見ただけでは、正確に何が起こっているのかを理解できませんでした。

したがって、次のオブジェクトがあるとします。

//file: MyClass.php
namespace MyClass;

class MyClass {

    public function say()
    {
        echo 'Hi';
    }
}

私はこのようなことをしたいと思います:

Monkeypatch\replace('MyClass', 'say', function() {
    echo 'Hello';
});

$obj = new MyClass();
$obj->say();  // Prints: 'Hello'

しかし、実際のパッチ部分をコーディングする方法がわかりません。このコンテキストでの名前空間が重要であることはわかっています。しかし、特定のメソッドにパッチを適用するにはどうすればよいのでしょうか? また、どこかで eval() を使用する必要がありますか (そうであれば、どのように)?

この問題に関する良い例を実際に見つけることができませんでした

しかし、それを自分のオブジェクト/メソッドに適用する方法が本当にわかりません。良い説明や例を期待しています。

4

5 に答える 5

4

runkitを使用してランタイム クラスの変更を行うことができます。具体的には、runkit_method_redefineを使用できます。

于 2012-04-08T18:35:48.637 に答える
3

http://till.klampaeckel.de/blog/archives/105-Monkey-patching-in-PHP.htmlの場合、実際に違いを生むのは、2番目のstrlenの前で使用される\文字です。

名前空間を使用している場合は、名前空間を使用しuseて、名前空間で宣言されているメソッド/クラスを直接呼び出すことができます。

use TheNamespace;
$var = new TheClass();

または、次のようなものを使用してクラスを明示的に呼び出します。

$var = new \TheNamespace\TheClass();

したがって、\strlen()代わりに呼び出すことによりstrlen()、この名前空間に定義されたstrlenではなく、デフォルトのstrlenを使用するようにPHPに明示的に要求します。

モンキーパッチについては、runkit( http://ca.php.net/runkit )を使用できます。また、パッチワークに関しては、彼らのWebサイト(http://antecedent.github.com/patchwork/docs/examples.html)にかなりの量の例があります。クラス内の関数を置き換えるマジックメソッドの例を確認できます。

于 2012-04-08T18:41:13.103 に答える
1

PHP 5.6 の時点では、モンキー パッチはまだサポートされていません。ただし、PHP 5.3 では無名関数が導入されました。この答えはまさにあなたが探しているものではなく、おそらく改善される可能性がありますが、一般的な考え方は、配列、無名関数、および参照を使用して、自己完結型の自己参照配列 (「オブジェクト」、場合は「オブジェクト」) を作成することです。あなたはするであろう):

test.php

$inner = require('test2.php');
$inner['say'](); // Hi!

$inner['data']['say'] = 'Bye!';
$inner['say'](); // still says Hi!

$inner['set_say']('Bye!');
$inner['say'](); // Bye!

$inner = require('test2.php');
$inner['say'](); // Hi!

test2.php

$class = array(
    'data' => array(
        'say' => 'Hi!'
    ),

    'say' => function() use (&$class){
        echo $class['data']['say'].'<br />';
    },

    'set_say' => function($msg) use (&$class){
        $class['data']['say'] =& $msg; 
    }
);

return $class;

また、上記のコード (PHP のモンキー パッチを含む) はほとんどの場合ひどい考えですが、これが絶対に必要な場合もあるという免責事項があります。

于 2015-04-23T19:13:30.370 に答える
0

eval() と名前空間を使用して、クラスにモンキー パッチを適用しました。ただし、モンキー パッチを適用しているクラスが既に名前空間にある場合、これは機能しないため、これは答えではないかもしれません。eval 文字列から名前空間宣言をトリミングする以外に、それを回避する方法がわかりません。ただし、これを行うと、クラス メソッド内の名前空間に依存するコードが破損する可能性があります。

私の場合、データベースの相互作用に依存するクラスを単体テストするために、コア PDO クラスにモンキー パッチを適用しています。しかし、私のテクニックを見ると、あなたの状況に合わせてそれを機能させる方法を理解するのに役立つかもしれません.

ここのブログ投稿にコード スニペットを掲載しています: http://chrisgriffing.com/coding/php/2012/04/12/how-to-mock-pdo-and-other-objects/

于 2012-04-16T23:33:29.450 に答える
-1

おそらくすでにこれを理解していると思いますが、参考までに、彼らはストリームラッパーを使用しています。

http://php.net/manual/es/function.stream-wrapper-register.php

基本的に、ファイルと phar にストリーム ラッパーを登録するため、コードがロードされたときにそれを操作できますが、opcache からロードされたコードでは機能しません。

于 2016-04-08T20:55:05.047 に答える