2012-04-08 87 views
4

我想弄清楚猴子修補是如何工作的以及如何讓它在我自己的對象/方法上工作。在PHP中修補猴子

我一直在尋找這樣的lib,這不正是我想要做自己: 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()(如果是這樣,如何)?

我真的無法找到有關此事的任何很好的例子,除了: http://till.klampaeckel.de/blog/archives/105-Monkey-patching-in-PHP.html

但我真的不知道怎樣才能應用,爲我自己的對象/方法。我希望有一個很好的解釋或例子。

回答

3

http://till.klampaeckel.de/blog/archives/105-Monkey-patching-in-PHP.html究竟是什麼讓差異的情況下在第二strlen的前面使用的\字符。

當您使用命名空間,你可以use命名空間並直接調用命名空間中聲明的方法/類:

use TheNamespace; 
$var = new TheClass(); 

,或者使用類似明確調用類:

$var = new \TheNamespace\TheClass();

所以通過調用\strlen()而不是strlen()您明確要求PHP使用de錯誤strlen而不是爲這個命名空間定義的strlen。

至於猴子補丁,你可以使用runkit(http://ca.php.net/runkit)。同樣在拼湊方面,他們的網站上有相當多的例子(http://antecedent.github.com/patchwork/docs/examples.html)。您可以檢查正在替換某個類中的函數的魔術方法示例。

+0

我瞭解webstie的strlen示例。但不是如何將這個應用於我自己的對象。它沒有說明如何重新定義拼湊方法。我也沒有找到任何像runkit等ohter庫。我只是想知道如何使用普通的PHP來修補自己的猴子。 – w00 2012-04-08 18:48:39

+0

@ w00在網站中提到的示例並不像您所能理解的那樣是猴子修補,因爲您可以通過名稱空間獲得整個觀點。這就是爲什麼你沒有得到任何覆蓋類內部函數的例子。如果您對猴子補丁的興趣嚴格限於單元測試,那麼您爲什麼不在開發服務器上使用runkit?否則,爲什麼你不拼湊拼湊試試?但是,我不知道它是否能夠擴大這種優勢。 – mobius 2012-04-08 19:16:34

4

您可以使用runkit執行運行時類修改。更具體地說,您可以使用runkit_method_redefine

+0

我不想使用runkit,它是一個pecl,它不能安裝在很多hosters上。另外,我對猴子補丁如何工作感興趣。如果我只想要一個圖書館,我會用拼湊而成的runkit。我只想知道如何修補猴子來修補我自己的對象。 – w00 2012-04-08 18:47:10

0

我有猴子補丁使用eval()和名稱空間的類。 但是,這可能不是您的答案,因爲如果您正在進行猴子修補的課程已經在名稱空間中,則這不起作用。 我還沒有想出如何解決這個問題,除了從eval字符串中修剪名稱空間聲明。但是,這樣做可能會破壞類方法中任何與命名空間相關的代碼。

就我而言,我是猴子修補核心PDO類,用於單元測試依賴於數據庫交互的類。但是,也許看到我的技術將幫助你弄清楚如何使它適合你的情況。

我的代碼在此處的博客文章網頁摘要起來: http://chrisgriffing.com/coding/php/2012/04/12/how-to-mock-pdo-and-other-objects/

1

隨着PHP 5.6的,還是有猴修補不支持;不過PHP 5.3引入了匿名函數。這個答案不是你正在尋找的東西,可能可以改進,但總的想法是使用數組,anonymous functionsreferences來創建一個自包含的自引用數組(如果你有一個「對象」會):

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中修補)幾乎總是一個可怕的想法,但有時候這是絕對必要的。