php get_class vs get_called_class and something about late static binding

之前有一篇笔记里面提到过get_class这个方法,这篇笔记主要是get_classget_called_class的区别,以及静态绑定相关的知识

假如说代码如下,有两个类,其中类B是类A的子类

  class A {
      public function test(){
         var_dump(get_class());
		 var_dump(get_called_class());
      }

      public static function test2(){
          var_dump(get_class());
		  var_dump(get_called_class());
      }
   }

   class B extends A {
	  public function test3(){
         var_dump(get_class());
		 var_dump(get_called_class());
      }

      public static function test4(){
          var_dump(get_class());
		  var_dump(get_called_class());
      }
   }

那么看下面这个打印出啥

	$varA = new A();
	$varA->test();
	A::test2();

打印结果是

string(1) "A"
string(1) "A"
string(1) "A"
string(1) "A"

看下面这个打印出啥

	$varB = new B();
	$varB->test();
	$varB->test3();
	B::test2();
	B::test4();

打印结果是

string(1) "A"
string(1) "B"
string(1) "B"
string(1) "B"
string(1) "A"
string(1) "B"
string(1) "B"
string(1) "B"

get_class($obj)的作用是:返回实例所属类的名字,如果在类里面可以省略参数。

get_called_class()的作用是:获取后期静态绑定("Late Static Binding")类的名称。该方法如果不是在类里面调用,会返回FALSE


我理解get_called_class()的作用就是获取最初调用这个方法的类名。比如说子类B调用父类A的方法,那么get_called_class()的结果就是B。但是手册上关于这个解释我觉得很奇怪,反而引入了一个新的概念——Late Static Binding

手册上对于Late Static Binding的解释是这样的:

“后期绑定”的意思是说,static:: 不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为“静态绑定”,因为它可以用于(但不限于)静态方法的调用。

什么鬼!就不能说人话吗!还是看看英文版吧。╭(╯^╰)╮

我在之前的笔记里面提到过,类的静态属性和静态方法,需要添加关键字static

而后期静态绑定(又叫:延迟绑定)也涉及到了static

static::中的static其实是运行时所在类的别名,并不是定义类时所在的那个类名。这个东西可以实现在父类中能够调用子类的方法和属性。

注意:static::与静态属性、静态方法不是同一个概念。


上面说了一大通,那么这个Late Static Binding到底有什么用呢?

说得简单点儿——父类可以调用子类的方法、属性。

以前在学校里学过一点点C++的时候,只知道子类可以调用父类的方法和属性,不知道还可以反过来的。那么下面就来看看实例。

举例:父类Model_Base,子类Model_User

class Model_Base { 

	public function getAll() {
		echo static::$table;
	}
} 

class Model_User extends Model_Base { 
    protected static $table = 'user'; 
}
	
$var = new Model_User();
$var->getAll();

打印结果是:

user

在父类Model_Base里面通过static::获取到了子类的静态属性。

如果大家觉得不够直观,那么示例可以改成如下这样,比较好理解。下面示例的意思就是,从user表和account表里面查出所有记录。

class Model_Base { 

	public function getAll() {		
		$tableName = static::$table;
		
		// 执行sql语句
		$sql = 'select * from ' . $tableName . ';';
		……
		// 返回数据库查询结果
		……
	}
} 

class Model_User extends Model_Base { 
    protected static $table = 'user'; 
}

class Model_Account extends Model_Base { 
    protected static $table = 'account'; 
}
	
$user = new Model_User();
$user->getAll();
	
$account = new Model_Account();
$account->getAll();

在上方的代码里面用到了static::,其实也可以用get_called_class来实现,比如

class Model_Base { 

	public function getAll() {		
		$clname = get_called_class();
		$tableName = $clname::$table;
		
		// 执行sql语句
		$sql = 'select * from ' . $tableName . ';';
		……
		// 返回数据库查询结果
		……
	}
} 

本文上面提到过,static::中static存放的是运行时所在类的别名,那么与get_called_class()的返回结果是一样的。


上面的举的例子是调用了子类的静态属性,那么调用子类的静态方法也是一样的。例子如下:

class Model_Base { 

	public function getAll() {		
		$clname = get_called_class();		
		$clname::info();
		
		echo "\n";
		
		static::info();
	}
} 

class Model_User extends Model_Base { 
    protected static $table = 'user'; 
	
	protected static function info() {
		echo 'table name is ' . self::$table;
	}
}
	
$var = new Model_User();
$var->getAll();

整个打印结果是:

table name is user
table name is user 

再次说明了get_called_class()static::里面的static所代表的类名是一样的。

上面都是调用静态属性、静态方法,如果是调用非静态属性、非静态方法呢?——看下面的例子

class Model_Base { 

	public function getAll() {		
		$u1 = new static();
		$u1->nameInfo();
		echo "\n";
		echo $u1->table;
		
		echo "\n";
		
		$clname = get_called_class();
		$u2 = new $clname();
		$u2->nameInfo();
		echo "\n";
		echo $u2->table;
	}
} 

class Model_User extends Model_Base { 
	
	protected $table = 'user';
	protected function nameInfo() {
		echo 'subclass table name is user';
	}
}
	
$var = new Model_User();
$var->getAll();

打印结果是:

subclass table name is user
user
subclass table name is user
user

上面的这个例子,可以看到非静态属性和非静态方法都能被调用。

Show Comments