Home » Code » PHP基础知识之——$this-self-parent-static关键字

PHP基础知识之——$this-self-parent-static关键字

基础很重要,今天就来补一下这些关键字。

$this

当一个对象要访问其方法时,会先完成一个绑定:将$this绑定到调用该方法的对象。方法谁调用,$this就指向谁。

$this的产生要存在于一个对象环境(object context)之中,且只有访问其非静态方法时才会产生!静态方法隶属于类,对象能调用,但此时不属于对象环境(个人理解)。

class AA
{
	public function foo()
	{
		var_dump($this);
	}

	public static function bar()
	{
		var_dump($this);
	}
}

AA::bar();//Notice: Undefined variable: this

$aa = new AA();
$aa->foo();
$aa->bar();//Notice: Undefined variable: this

self

self永远指向定义它的类。也就是你在哪里写了self,self就代表哪个类。

class AA
{
	public $name = 'AA <br/>';

	public static $age = 'AA 12 <br/>';

	public function foo()
	{
		echo self::$age;

		echo self::$name;//Fatal error: Access to undeclared static property: AA::$name

		echo self->$name;//Parse error
	}

}

class BB extends AA
{
	public $name = 'BB <br/>';

	public static $age = 'BB 12 <br/>';

}

$bb = new BB();
$bb->foo();//AA 12,虽然是BB的实例,但foo是A中定义的,self就指向A

$this绑定的是调用方法的对象,是对象级别,self则是绑定的定义它的类,是类级别。因此只能用于访问静态方法或静态属性或常量。

parent

跟self类似,parent指向的是定义它的类的父类。也是类级别。

class AA
{
	public $name = 'AA <br/>';

	public static $age = 'AA 12 <br/>';
}

class BB extends AA
{
	public $name = 'BB <br/>';

	public static $age = 'BB 12 <br/>';

	public function foo()
	{
		echo self::$age;//BB 12 

		echo parent::$age;//AA 12 

		echo parent::$name;//Fatal error: Access to undeclared static property: AA::$name

		//echo parent->$name;//Parse error
	}

}

$bb = new BB();
$bb->foo();

static

static关键字是PHP 5.3时引入的,官方名称是延迟静态绑定(late-static-bindings)。static关键字可以在父类中引用到扩展类的最终状态,也就是指向调用它的类。换句话,当碰到static关键字时,static就指向了当前的调用域(calling scope),而不是像self、__CLASS__等静态引用会寻找定义他们的域。看实例:

class AA
{
	public static $age = 'AA 12 <br/>';

	public function foo()
	{
		echo self::$age;//AA 12 
		echo static::$age;//BB 12
		static::bar();//BB bar(
		static::bar1();//BB bar1()

	}
}

class BB extends AA
{
	public static $age = 'BB 12 <br/>';

	public static function bar()
	{
		echo 'BB bar() <br/>';
	}

	public function bar1()
	{
		echo 'BB bar1() <br/>';
	}
}

$bb = new BB();
$bb->foo();

可以看到,static关键字绑定了调用方法的类,而不是定义方法的类(foo()方法是在AA中定义的,static绑定的是调用它的BB)。一来来说,static用于调用调用类的静态方法但不限于静态方法,例子中BB中的bar1()就是非静态的,一样可以正常运行,不像self、parent一样会出错,但毕竟是类级别的绑定,还是必须使用::而不能使用->。

手册上有这么一句话:后期静态绑定的解析会一直到取得一个完全解析了的静态调用为止。另一方面,如果静态调用使用 parent:: 或者self:: 将转发调用信息。附加的例子也被面试者经常拿来考人。

class A {
    public static function foo() {
        static::who();
    }

    public static function who() {
        echo __CLASS__."\n";
    }
}

class B extends A {
    public static function test() {
        A::foo();//A调用A自己的foo(),static指向调用者当然为A

        parent::foo();//parent指的是当前类的父类A,调用者依然是C,
        	//parent只是起到了“转发调用者”的作用。
        	//A中的foo内的static解析到C,最后运行的是C的who(),输出的是__CLASS__为C

        self::foo();//同样的转发调用者,是C要调用B中的foo(),
       		//千万不要理解为是B要调用B自己的foo()。这样理解的话结果就是B了。
    }

    public static function who() {
        echo __CLASS__."\n";
    }
}

class C extends B {
    public static function who() {
        echo __CLASS__."\n";
    }
}

C::test();//test()来自B。结果为A C C

要注意所谓的“转发调用信息”。

手册上在非静态环境下使用static的例子引还引起了我的注意,不是不理解static,而是对$this的行为让人诧异。

原例子是说的这么一个事:

class A
{
	private function foo()
	{
		echo 'A foo()<br/>';
	}

	public function test()
	{
		$this->foo();//调用A类的foo()
		static::foo();
		//调用C类的foo(),Fatal error: Call to private method C::foo() from context 'A' 
	}
}

class C extends A
{
	private function foo()
	{
		echo 'C foo()<br/>';
	}
}

$c = new C();
$c->test();

static那里,是调用的C中的foo(),在A的环境中调用C中的私有方法,肯定是不行的,这个不难理解。我的困惑是使用$this->foo()时怎么就运行的是A的foo(),为何不跟使用static时一样调用C中的foo(),这里的$this显然绑定的是C 的实例。如果将A中的foo定义为protected或者public,这时当然C中的private也得改一下(限制级不能比父类的还要严格)。现在问题变为讨论$this,跟static无关:

class A
{
	private function foo()
	{
		echo 'A foo()<br/>';
	}

	public function test()
	{
		$this->foo();//如果当前类中有foo且为private,会被运行。否则运行子类的
	}
}

class C extends A
{
	public function foo()
	{
		echo 'C foo()<br/>';
	}
}

$c = new C();
$c->test();//A中的foo()为private,运行A的。否则运行C的

这么一个结果很是奇怪,test()中的$this明明是C的实例,C中又有公开的foo(),为何还是调用的A中的foo()。对于这么一个结果,询问了两个群里的大神,有的同样表示不懂了,有的扯个半天没说到点子,最后有的还说我基础不懂回去看书或者文档,还说出$this就是get_class()这样的话来,This time only hehe送给他们。。。

面对这么一个状况,我只有把手册上的话记住:

$this-> will try to call private methods from the same scope

自己个人理解:使用$this时,如果当前类有private的方法,会优先调用之,然后再去考虑子类的方法。

参考链接:
http://www.wintercoder.com/478.html
http://bug1874.com/archives/247

One comment

  1. 在非静态环境下,所调用的类即为该对象实例所属的类。由于 $this-> 会在同一作用范围内尝试调用私有方法,而 static:: 则可能给出不同结果。

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Time limit is exhausted. Please reload CAPTCHA.