我一直在看php反射方法,我想要做的是在方法打开之后和任何返回值之前注入一些代码,例如我想要改变:
function foo($bar)
{
$foo = $bar ;
return $foo ;
}
并将一些代码注入其中:
function foo($bar)
{
//some code here
$foo = $bar ;
//some code here
return $foo ;
}
可能?
答案 0 :(得分:5)
嗯,一种方法是将所有方法调用设为“虚拟”:
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
它将对象的实例作为第一个方法传递给“覆盖”。注意:此“覆盖”方法将无法访问该类的任何受保护成员。因此,请使用getter(__get
,__set
)。它可以访问受保护的方法,因为实际的调用来自__call()
...
注意:您需要修改所有默认方法,并以“_”为前缀,以便工作...(或者您可以选择其他前缀选项,或者您可以范围他们都受到保护)...
答案 1 :(得分:2)
查看anonymous functions。如果您可以运行PHP 5.3,那可能更符合您的尝试。
答案 2 :(得分:2)
这是不可能的,至少不是你想要的方式。正如评论所建议的那样,反思是获取有关类/函数的信息,而不是修改它们。
有一个名为Runkit的PHP扩展,我认为它提供了这种类型的功能 - http://www.php.net/manual/en/book.runkit.php,但是默认情况下绝大多数主机都不会安装它。
虽然可能有不同的方法。也许如果你可以提供一些关于你想要做什么的更多信息,以及为什么你不能修改有问题的函数,我们也许可以提供一些指示。例如。是你想要修改核心PHP函数的函数,还是你不想编辑的第三方库中的代码?
答案 3 :(得分:0)
只是一个想法:
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;
}
答案 4 :(得分:0)
您可以在原始自动加载器之前添加一个特殊的自动加载器,读取原始自动加载将加载的文件,更改内容,将该文件保存在其他位置(例如某些tmp目录)并包含该修改后的文件而不是原始文件
答案 5 :(得分:0)
我想做同样的事情,所以我创建了一个通用的检测类,它将取代我试图检测的类,并利用@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)
为$instrumentationOn
或true
,则呼叫false
的工作方式相同(与@ircmaxell回答相同)。如果它是true
,它只会做额外的计时。
答案 6 :(得分:-1)
也许我错过了一些东西,但是你真的想像你说的那样“注入”代码吗?你想要实现什么目标?如果你只想在A发生时执行一个代码块,而在B发生时再执行另一个代码块,那么你只需要简单的编程逻辑,就像if()语句一样。
你真的想在运行时改变一个功能吗?或者这只是一个逻辑问题?
更具体地说明您需要做什么。