Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/asp.net-mvc-3/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 在运行时修改方法/函数_Php_Reflection - Fatal编程技术网

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,那么这可

我一直在研究php反射方法,我想做的是在方法打开后和任何返回值之前插入一些代码,例如,我想更改:

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