Php 在运行时修改方法/函数
我一直在研究php反射方法,我想做的是在方法打开后和任何返回值之前插入一些代码,例如,我想更改:Php 在运行时修改方法/函数,php,reflection,Php,Reflection,我一直在研究php反射方法,我想做的是在方法打开后和任何返回值之前插入一些代码,例如,我想更改: function foo($bar) { $foo = $bar ; return $foo ; } 并向其中注入一些代码,如: function foo($bar) { //some code here $foo = $bar ; //some code here return $foo ; } 可能吗?调查。如果您可以运行PHP5.3,那么这可
function foo($bar)
{
$foo = $bar ;
return $foo ;
}
并向其中注入一些代码,如:
function foo($bar)
{
//some code here
$foo = $bar ;
//some code here
return $foo ;
}
可能吗?调查。如果您可以运行PHP5.3,那么这可能更符合您的目标。这是不可能的,至少您所追求的方式是不可能的。正如评论所建议的,反射是为了获取关于类/函数的信息,而不是修改它们 有一个名为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;
}
一种方法是将所有方法调用都设置为“虚拟”: 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
它将对象的实例作为第一个方法传递给“override”。注意:此“重写”方法将无权访问该类的任何受保护成员。因此,请使用getter(\uu get
,\uu set
)。它可以访问受保护的方法,因为实际调用来自\uu call()
注意:您需要修改所有默认方法,将其前缀改为“\ux”,才能使其正常工作。。。(或者你可以选择另一个前缀选项,或者你可以只对它们进行保护).也许我遗漏了什么,但是你真的想像你说的那样“注入”代码吗?你想达到什么目标?如果只想在A发生时执行一个代码块,在B发生时执行另一个代码块,那么只需要简单的编程逻辑,比如If()语句 你真的想在运行时修改函数吗?或者这只是一个逻辑问题
更具体地说明你需要做什么 您可以在原始自动加载器之前添加一个特殊的自动加载器,读取原始自动加载器将加载的文件,更改内容,将该文件保存到其他地方(例如某些tmp目录),并包含修改后的文件而不是原始文件。我想做完全相同的事情,因此,我创建了一个泛型插装类,它将替换我试图插装的类,并利用@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;
}
}
如果
$instrumentationOn
为true
或false
,则调用$myClass->foo($bar)
的工作原理相同(与@ircmaxell answer的警告相同)。如果它是真的
它只会做额外的计时工作。我不认为你想要的是可能的。我可能错了,但在一般情况下,反射API用于获取有关类等的信息,而不是在运行时更改代码。请提供有关您尝试执行的操作的更多信息,也许我们可以帮助找到不同的解决方案。我确信有解决方案,并且您知道您需要它-您确定这是您想要的吗?为什么要在运行时更改函数的性质?更好的选择可能是传入一个控制函数流的变量;或者可能考虑使用EVAL()语句来运行代码。这样想:一个没有预先确定的效果的函数叫什么名字?感谢replys的家伙们,基本上我正在尝试启用每个函数的评测,而不必使用评测扩展(xdebug、xhprof、apd)。作为我开发的框架的一部分。因此,这两个插入将用于计时、内存使用和添加到会话变量,以便我可以内联输出数据。不需要处理cachegrind文件等。好主意。。。尽管我可能会将$preprocess和$postprocess放入回调('functionname'或array('classname','methodname')),并使用call_user_func调用它们。这可能会影响范围,但这也会使IMHO更安全。我的应用程序中的所有方法都需要这样做,并且我希望它保持干净。在我发布此评论时,Runkit是beta版,但它不会编译(尝试在linux上使用php 5.3.19编译时出现错误)
<?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 = new ClassWithFoo();
if ($instrumentationOn) {
$myClass = new GenericClassInstrumentor($myClass);
}