重构函数和反射

2个知识点

  1. 重写内置函数
  2. 访问私有方法或者变量

重写内置函数

代码如下

<?php
function sha1(){
    return 'success';
}
echo sha1();
?>

这样直接重写一个sha1函数会报错
Fatal error: Cannot redeclare sha1() in C:\Users\j7ur8\Desktop\php\index.php on line 5 可以试试增加一个namespace,代码如下

<?php
namespace interesting;
function sha1(){
    return 'success';
}
echo sha1();

成功返回success。我们可以把平常我们编写代码时调用的方法想象成是一个public类的方法,也就是我们本来就在一个public函数中编写代码,调用public内置的方法。php支持使用namespace来解释重复出现的变量和方法,所以我们可以使用namespace来重写namespace下的sha1函数。

访问私有方法或者属性

利用反射Reflecttion(PHP 5, PHP 7)

调用私有方法

<?php  
class Example1{ 
    private $_prop = 'test'; 
} 

$r = function(Example1 $e){ 
    return $e->_prop; 
}; 

$a = new Example1(); 
$rfp = new ReflectionProperty('Example1','_prop'); 
$rfp->setAccessible(true); 
var_dump($rfp->getValue($a)); 

//结果输出:string 'test' (length=4) 
?>

带参数的

public function callPrivateMethod($object, $methodName)
{
    $reflectionClass = new \ReflectionClass($object);
    $reflectionMethod = $reflectionClass->getMethod($methodName);
    $reflectionMethod->setAccessible(true);

    $params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
    return $reflectionMethod->invokeArgs($object, $params);
}

私有属性

<?php
class Foo {
  private function myPrivateMethod() {
    return 7;
  }
}

$method = new ReflectionMethod('Foo', 'myPrivateMethod');
$method->setAccessible(true);

echo $method->invoke(new Foo);
// echos "7"
?>

反射命名空间

反射一个类也可以通过反射命名空间来搞 国赛中的payload为:

<?php
$ref_class=new ReflectionClass('\interesting\FlagSDK');
$instance=$ref_class->newInstance();
$method=$ref_class->getmethod('getHash');
$method->setAccessible(true);
echo $method->invoke($instance);
?>

无论是反射方法还是属性都有一步时setAccessible,关于反射属性和方法也还有一些其他方法。

利用Closure类(PHP 5 >= 5.3.0, PHP 7)

访问属性

<?php  
class Example1{ 
    private $_prop = 'test'; 
} 

$r = function(Example1 $e){ 
    return $e->_prop; 
}; 

$a = new Example1(); 
$r = Closure::bind($r,null,$a); 

var_dump($r($a)); 

//结果输出:string 'test' (length=4)

更改属性

<?php  
class Example1{ 
    private $_prop = 'test'; 
} 

$a = new Example1(); 
$r = Closure::bind(function & (Example1 $e) { 
    return $e->_prop; 
}, null, $a); 

$cake = & $r($a); 
$cake = 'lie'; 
var_dump($r($a));

利用Closure类访问方法

PHP7可使用
<?php
class Foo {
    private $bar = "Foo::Bar";
    private function add_ab($a, $b) {
        return $a + $b;
    }
}
$foo = new Foo;
$getFooBar = function() {
    return $this->bar;
};
echo $getFooBar->call($foo); 

$getFooAddAB = function() {
    return $this->add_ab(func_get_args()[0],func_get_args()[1]);
};//func_get_arg(0)
var_dump($getFooAddAB->call($foo, 33, 6)); // Prints 39
PHP5和PHP7可使用
<?php
class Foo {
    private $bar = "Foo::Bar";
    private function add_ab($a, $b) {
        return $a + $b;
    }
}
$foo = new Foo;
$getFooBarCallback = function() {
    return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar


$getFooAddABCallback = function() {
    return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6);

参考

results matching ""

    No results matching ""