5

Вопрос по php – исправление обезьян в 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

Но я действительно не вижу, как я могу применить это к своим собственным объектам / методам. Я надеюсь на хорошее объяснение или пример.

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

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

    от
  • Я не хочу использовать runkit, это pecl, и его нельзя установить на многих хостерах. Кроме того, меня интересует, как работает исправление обезьян. Если бы я просто хотел библиотеку, я бы использовал runkit на пэчворке. Я просто хочу знать, как исправление обезьяны будет работать с исправлениями моих собственных объектов.

    от w00
5 ответов
  • 4

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

    runkit, Более конкретно, вы можете использоватьrunkit_method_redefine.

  • 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 использовать strlen по умолчанию, а не strlen, определенный для этого пространства имен.

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

  • 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 ввел анонимные функции. Этот ответ не совсем то, что вы ищете, и, возможно, его можно улучшить, но общая идея состоит в том, чтобы использовать массивы,анонимные функции, а такжеРекомендации чтобы создать автономный, самоссылающийся массив («объект», если хотите):

    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;
    

    Также,here's a disclaimer Сказать, что приведенный выше код (наряду с патчами для обезьян в PHP) почти всегда ужасная идея, но бывают случаи, когда это абсолютно необходимо.

  • -1

    Вы

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

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

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