Я рассматривал методы отражения 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 ().
Вы действительно пытаетесь изменить функцию во время выполнения? Или это просто логическая проблема?
Будьте более конкретными в том, что вам нужно делать.