您的位置:首页 > 编程语言 > PHP开发

利用php中的eval来模拟java中的动态代理

2010-04-28 10:44 537 查看
使用java中的动态代理可以完成很多事情,比如将业务实例进行托管,实现AOP等,但是Php中没有实现这样的东西,昨天突然想到其实可以通过eval来模拟一个动态代理机制。php比java不同的是,php是不需要编译的,因此只要我们能够动态生成一段代码,然后用eval来执行就可以达到效果。代码如下:

/**
* 代理实现类
*/
interface IInvocationHandler
{
function invoke($method, array $arr_args);
}
/**
* 代理类
*/
final class Proxy
{
const CLASS_TEMPLATE = '
final class %s implements %s
{
private $handler;
public function __construct(IInvocationHandler $handler)
{
$this->handler = $handler;
}
%s
}
';
const FUNCTION_TEMPLATE = '
public function %s(%s)
{
$arr_args = func_get_args ();
$arr_method = explode("::", __METHOD__);
$this->handler->invoke ( $arr_method[1], $arr_args );
}
';
public static function newProxyInstance(array $arr_interface, IInvocationHandler $handler)
{
$className = self::getClassName ( $arr_interface );
if (class_exists ( $className ))
{
return new $className ( $handler );
}
self::checkInterfaceExists ( $arr_interface );
self::generateClass ( $arr_interface );
return new $className ( $handler );
}
protected static function generateClass(array $arr_interface)
{
$className = self::getClassName ( $arr_interface );
$interfaceList = implode ( ',', $arr_interface );
$functionList = '';
foreach ( $arr_interface as $interface )
{
$class = new ReflectionClass ( $interface );
$arr_method = $class->getMethods ();
foreach ( $arr_method as $method )
{
$methodName = $method->getName ();
$arr_parameter = $method->getParameters ();
$parameterArray = array ();
foreach ( $arr_parameter as $parameter )
{
$parameterName = $parameter->getName ();
$parameterArray [] = '$' . $parameterName;
}
$parameterList = implode ( ',', $parameterArray );
}
$functionList .= sprintf ( self::FUNCTION_TEMPLATE, $methodName, $parameterList );
}
$code = sprintf ( self::CLASS_TEMPLATE, $className, $interfaceList, $functionList );
eval ( $code );
}
protected static function checkInterfaceExists(array $arr_interface)
{
foreach ( $arr_interface as $interface )
{
if (! interface_exists ( $interface ))
{
throw new Exception ( "interface $interface do not loaded" );
}
}
}
protected static function getClassName(array $arr_interface)
{
return 'Class_' . implode ( '_', $arr_interface ) . '_Implementation';
}
}
class Test implements ITest1, ITest2
{
/**
* @see ITest1::test1()
*
* @param unknown_type $arg1
* @param unknown_type $arg2
*/
function test1($arg1, $arg2)
{
echo "Test::test1($arg1, $arg2)/n";
return "ok";
}
/**
* @see ITest2::test2()
*
*/
function test2()
{
echo "Test::test2()/n";
return "failed";
}
}
class Target implements IInvocationHandler
{
private $target;
public function __construct()
{
$this->target = new Test ( );
}
/**
* @see IInvocationHandler::invoke()
*
* @param ReflectionMethod $method
* @param array $arr_args
*/
function invoke($methodName, array $arr_args)
{
$method = new ReflectionMethod ( 'Test', $methodName );
echo "before call method $methodName/n";
$ret = $method->invokeArgs ( $this->target, $arr_args );
echo "after call method $methodName return $ret/n";
return $ret;
}
}
interface ITest1
{
function test1($arg1, $arg2);
}
interface ITest2
{
function test2();
}
$proxy = Proxy::newProxyInstance ( array ('ITest1', 'ITest2' ), new Target ( ) );
$proxy->test2 ();
$proxy = Proxy::newProxyInstance ( array ('ITest1' ), new Target ( ) );
$proxy->test1 ( 'a', 1 );


其实从这个例子可以推出来,我们甚至可以模拟asm的相关功能,而且实现要比java简单很多。看来以前没有挖掘php的功能呀,这个语言被我低估了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: