2012-04-08 5 views
4

Я пытаюсь выяснить, как работает патч обезьян и как я могу заставить его работать над своими собственными объектами/методами.Прыжки обезьян в php

Я смотрел на этой библиотеке, он делает именно то, что я хочу сделать сам: 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 то, что на самом деле делает разницу, является символ \, используемый перед второй стролей.

При использовании пространств имен вы можете use пространство имен и непосредственно ссылаться на методы/классы, объявленные в пространстве имен:

use TheNamespace; 
$var = new TheClass(); 

Или вызовите класс явно используя что-то вроде:

$var = new \TheNamespace\TheClass();

Итак, вызывая \strlen() вместо strlen(), вы явно обращаетесь к PHP с просьбой использовать de fault strlen, а не strlen, определенный для этого пространства имен.

Что касается патчей обезьян, вы можете использовать runkit (http://ca.php.net/runkit). Также в отношении лоскутного одеяла на их веб-сайте имеется множество примеров (http://antecedent.github.com/patchwork/docs/examples.html). Вы можете проверить пример магического метода, который заменяет функцию в классе.

+0

Я понимаю пример strlen из webstie. Но не как применять это на моих собственных объектах. Он не говорит, как переопределить методы, подобные тому, как это делается в лоскутной одежде. Я также не ищу какую-либо библиотеку ohter, такую ​​как runkit и т. Д. Я просто хочу знать, как сделать обезьянную патчу самостоятельно с помощью простого PHP. – w00

+0

@ w00 Пример, упомянутый на веб-сайте, не является патчем обезьян, как вы можете понять, поскольку вы получаете всю точку с пространствами имен. Вот почему вы не получаете никаких примеров переопределения функций внутри классов. Если ваш интерес к патчу обезьян строго для модульного тестирования, то почему бы вам не использовать runkit на вашем сервере разработки? Иначе почему бы вам не попробовать попробовать пэчворк? Однако я не знаю, насколько это хорошо. – mobius

4

Вы можете выполнить модификацию класса времени выполнения, используя runkit. В частности, вы можете использовать runkit_method_redefine.

+0

Я не хочу использовать runkit, это клюшка, и она не может быть установлена ​​на много хостеров. Кроме того, меня интересует, как работает патч обезьян. Если бы я просто хотел библиотеку, я бы использовал runkit на лоскутной одежде. Я просто хочу знать, как патч обезьяны будет работать с исправлением моих собственных объектов. – w00

0

У меня есть обезглавленный класс, используя eval() и пространства имен. Возможно, это не ответ для вас, так как это не работает, если класс, который вы используете для исправления обезьян, уже находится в пространстве имен. Я не понял, как обойти это, кроме обрезки объявления пространства имен из строки eval. Однако выполнение этого, вероятно, приведет к нарушению любого кода, зависящего от пространства имен, в методах класса.

В моем случае я обезвреживаю основной класс PDO для модульного тестирования класса, который зависит от взаимодействия с базой данных.Но, возможно, видя мою технику, вы сможете понять, как заставить ее работать на вашу ситуацию.

У меня есть фрагменты кода в блоге здесь: http://chrisgriffing.com/coding/php/2012/04/12/how-to-mock-pdo-and-other-objects/

1

В РНР 5.6, что до сих пор нет поддержки обезьяны заплат; однако PHP 5.3 представил анонимные функции. Этот ответ не совсем то, что вы ищете, и, вероятно, его можно улучшить, но общая идея состоит в том, чтобы использовать массивы, anonymous functions и references, чтобы создать автономный самореферентный массив («объект», если вы будет):

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) почти всегда является ужасной идеей, но бывают случаи, когда это абсолютно необходимо.

-1

вы, вероятно, уже поняли это, но только для справки, они используют поток обертки,

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

в основном, они регистрируют поток обертку на файл и Phar, поэтому, когда код загружается , thay может манипулировать им, он не работает с кодом, загруженным из opcache

Смежные вопросы