изменить метод / функцию во время выполнения

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

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

И добавьте в него код:

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

возможное?

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

Ну, в любом случае, чтобы все методы вызывали «виртуальные»:

 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 

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

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

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

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

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

Просто идея:

 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; } в 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; } в 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; } 

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

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

 <?php class GenericClassInstrumentor { private $instrumentedClass; private $className; public function __construct($instrumentedClass) { $this->instrumentedClass = $instrumentedClass; $this->className = get_class($instrumentedClass); } public function __call($name, $arguments) { $start = microtime(true); $result = call_user_func_array(array($this->instrumentedClass, $name), $arguments); $end = microtime(true); $duration = ($end - $start) * 1000; // optionally log something here return $result; } } 

Скажем, у вас был экземпляр класса, такого как $myClass , который имел функцию foo на нем, тогда вы бы сделали что-то вроде этого:

 $myClass = new ClassWithFoo(); if ($instrumentationOn) { $myClass = new GenericClassInstrumentor($myClass); } 

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

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

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

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