изменить метод / функцию во время выполнения - PullRequest
8 голосов
/ 28 мая 2010

Я смотрел на методы отражения php, что я хочу сделать, это ввести некоторый код после открытия метода и перед любым возвращаемым значением, например, я хочу изменить:

function foo($bar)
{
    $foo = $bar ;
    return $foo ;
}

И внедрить в него некоторый код, например:

function foo($bar)
{
    //some code here
    $foo = $bar ;
    //some code here
    return $foo ;
}

возможно

Ответы [ 7 ]

5 голосов
/ 28 мая 2010

Ну, одним из способов было бы сделать все вызовы методов "виртуальными":

class Foo {
    protected $overrides = array();

    public function __call($func, $args) {
        $func = strtolower($func);
        if (isset($this->overrides[$func])) {
            // We have a override for this method, call it instead!
            array_unshift($args, $this); //Add the object to the argument list as the first
            return call_user_func_array($this->overrides[$func], $args);
        } elseif (is_callable(array($this, '_' . $func))) {
            // Call an "internal" version
            return call_user_func_array(array($this, '_' . $func), $args);
        } else {
            throw new BadMethodCallException('Method '.$func.' Does Not Exist');
        }
    }

    public function addOverride($name, $callback) { 
        $this->overrides[strtolower($name)] = $callback;
    }

    public function _doSomething($foo) {
        echo "Foo: ". $foo;
    }
}

$foo = new Foo();

$foo->doSomething('test'); // Foo: test

PHP 5.2:

$f = create_function('$obj, $str', 'echo "Bar: " . $obj->_doSomething($str) . " Baz";');

PHP 5.3:

$f = function($obj, $str) {
    echo "Bar: " . $obj->_doSomething($str) . " Baz";
}

Все PHP:

$foo->addOverride('doSomething', $f);

$foo->doSomething('test'); // Bar: Foo: test Baz

Он передает экземпляр объекта в качестве первого метода для «переопределения».Примечание. Этот переопределенный метод не будет иметь доступа ни к каким защищенным членам класса.Так что используйте геттеры (__get, __set).Он будет иметь доступ к защищенным методам, так как фактический вызов поступает с __call() ...

Примечание: Вам нужно будет изменить все ваши методы по умолчанию, добавив префикс'_' для того, чтобы это работало ... (или вы можете выбрать другой параметр префикса, или вы можете просто ограничить область их защиты) ...

2 голосов
/ 28 мая 2010

Это невозможно, по крайней мере, не так, как вы. Как отмечается в комментарии, рефлексия предназначена для получения информации о классах / функциях, а не их изменения.

Существует расширение PHP под названием Runkit, которое, я считаю, предоставляет такой тип функциональности - http://www.php.net/manual/en/book.runkit.php,, однако оно не будет установлено по умолчанию на подавляющем большинстве хостов.

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

2 голосов
/ 28 мая 2010

Просмотр анонимных функций . Если вы можете запустить PHP 5.3, это может быть больше в соответствии с тем, что вы пытаетесь сделать.

0 голосов
/ 03 ноября 2015

Я хотел сделать точно такую ​​же вещь, поэтому я создал общий инструментальный класс, который заменит класс, который я пытался использовать, и использую технику @ircmaxell, которую он будет вызывать для инструментируемого класса.*

Скажем, у вас есть экземпляр класса типа $myClass, в котором есть функция foo, тогда вы сделаете что-то вроде этого:то же самое (с теми же оговорками, что и при ответе @ircmaxell), если $instrumentationOn равно true или false.Если это true, это просто добавит время.

0 голосов
/ 06 мая 2014

Вы можете добавить специальный автозагрузчик перед исходным автозагрузчиком, прочитать файл, который будет загружать ваша оригинальная автозагрузка, изменить содержимое, сохранить этот файл где-нибудь еще (например, в некотором каталоге tmp) и включить этот измененный файл вместо исходного. .

0 голосов
/ 28 мая 2010

Может быть, я что-то упускаю, но вы действительно хотите «внедрить» код, как вы говорите? Чего ты пытаешься достичь? Если вы просто хотите выполнить один блок кода, когда происходит A, а другой - когда B, тогда все, что вам нужно, - это простая логика программирования, например, оператор if ().

Вы действительно пытаетесь изменить функцию во время выполнения? Или это просто логическая проблема?

Будьте более конкретны в том, что вам нужно сделать.

0 голосов
/ 28 мая 2010

Просто идея:

function foo($bar, $preprocess, $postprocess){

    //IF CONDITION($preprocess)
    include('/mylogic/'.$preprocess.".php"); //do some preprocessing here?
    $foo = $bar ;
    //IF CONDITION($postprocess)
    include('/mylogic/'.$postprocess.".php"); //process $foo here?
    //FINALLY return
    return $foo;

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...