在每个面向对象编程语言中都会涉及到一个指向当前对象的值,this( 当然,python不是的)。但是this本身在很多时候都是有"歧义"的,因为不同的理解容易造成意想不到的bug产生。
比如在jquery中的ajax请求,经常会看到下面的代码:
$('#button').click(function(){
var that = this;
$.ajax({
url:'/xxxx/xxxx',
'data':{},
'success':function(res){
if(res.code == 0)
{
$(that).hide();
}
}
})
})
之所以需要在请求之前将this对象赋值给that,是因为在成功回调函数中的"this"并不是之前的"this"了。除了通过一个临时变量that保存之外,还可以使用bind的方式制定this。
相同的,在php中也存在回调函数,匿名类对象,闭包等。这些场景都会导致this的指向内容歧义化。
class TestFoo {
public $foo = 'TestFoo';
public function getCallback(){
$currentFoo = $this->foo;
return function() use ($currentFoo) {
echo 'current '.$currentFoo.',callback '.$this->foo."\n";
};
}
}
$testFoo = new TestFoo();
$closure = $testFoo->getCallback();
call_user_func_array($closure, []);
$context = new \StdClass;
$context->foo = "Hello World";
$boundClosure = $closure->bindTo($context);
$boundClosure();
上面代码分别是输出
current TestFoo,callback TestFoo
current TestFoo,callback Hello World
在php5.4之前的版本,上面的代码其实是会有问题的。必须要写成that的形式
class TestFoo {
public $foo = 'TestFoo';
public function getCallback(){
$currentFoo = $this->foo;
$that = $this;
return function() use ($currentFoo,$that) {
echo 'current '.$currentFoo.',callback '.$that->foo."\n";
};
}
}
对于匿名类,则会有更加复杂的
class TestFoo {
public $foo = 'TestFoo';
protected $logger;
public $name = "out";
public function getCallback(){
$currentFoo = $this->foo;
$this->testInnerClass(new class {
private $name = "innerlogger";
public function log($msg)
{
echo $this->name.' log '.$msg."\n";
}
});
$this->logger->log('test');
return function() use ($currentFoo) {
echo 'current '.$currentFoo.',callback '.$this->foo."\n";
};
}
public function testInnerClass($log){
$this->logger = $log;
}
}
$testFoo = new TestFoo();
$closure = $testFoo->getCallback();
call_user_func_array($closure, []);
上面代码输出内容是:
innerlogger log test
current TestFoo,callback TestFoo
通过上面的分析,相信大家对this
会有新的认识。在编码过程中,要注意this
对象的实际指向,避免产生不必要的bug。这种问题,如果产生bug,是很难排查的。