不灭的焱

革命尚未成功,同志仍须努力

作者:php-note.com  发布于:2015-02-11 19:26  分类:PHP基础 

PHP里的__CLASS__这类东西是静态绑定的,如果不在子类里重载的话,那么继承父类方法所得到的依旧是父类的名称,而不是子类的名称,比如:

<?php
class A {
	function __construct() {
		echo __CLASS__;
	}

	static function name() {
		echo __CLASS__;
	}
}

class B extends A {
}

$objB = new B(); // 输出 A
B::name();       // 输出 A

此时,无论将B实例化还是直接调用静态方法,echo出来的都会是A。

 

而实际上我想要得到的是子类B的名称!那如何实现呢?

PHP自带两个函数 get_class()get_called_class() 可以解决这个问题。

get_class()用于实例调用,加入参数($this)可解决子类继承调用的问题,而get_called_class()则是用于静态方法调用。

需要注意的是get_called_class()需要 PHP>=5.3.0 才支持,官方手册:http://php.net/manual/en/function.get-called-class.php,对于 PHP5.3.0以下的版本,有人给出了如下实现方式:

<?php
if (!function_exists('get_called_class')) {
	class classTools {
		private static $i = 0;
		private static $file = null;

		public static function get_called_class() {
			$bt = debug_backtrace();

			// 使用 call_user_func 或 call_user_func_array 函数调用类方法,处理如下
			if (array_key_exists(3, $bt) && array_key_exists('function', $bt[3]) && in_array($bt[3]['function'], array('call_user_func', 'call_user_func_array'))
			) {
				// 如果参数是数组
				if (is_array($bt[3]['args'][0])) {
					$toret = $bt[3]['args'][0][0];

					return $toret;
				} else if (is_string($bt[3]['args'][0])) {
					// 如果参数是字符串
					// 如果是字符串且字符串中包含::符号,则认为是正确的参数类型,计算并返回类名
					if (false !== strpos($bt[3]['args'][0], '::')) {
						$toret = explode('::', $bt[3]['args'][0]);

						return $toret[0];
					}
				}
			}

			// 使用正常途径调用类方法,如:A::make()
			if (self::$file == $bt[2]['file'] . $bt[2]['line']) {
				self::$i++;
			} else {
				self::$i = 0;
				self::$file = $bt[2]['file'] . $bt[2]['line'];
			}
			$lines = file($bt[2]['file']);
			preg_match_all('/([a-zA-Z0-9\_]+)::' . $bt[2]['function'] . '/', $lines[$bt[2]['line'] - 1], $matches);

			return $matches[1][self::$i];
		}
	}

	function get_called_class() {
		return classTools::get_called_class();
	}
}

现在,把例子修改下:

<?php
class A {
	function __construct() {
		echo get_class($this);
	}

	static function name() {
		echo get_called_class();
	}
}

class B extends A {
}

$objB = new B(); // 输出 B
B::name();       // 输出 B

呵呵,这是我想要的结果!

 

 

延伸阅读:

PHP get_class 返回对象的类名

PHP get_class_methods函数用法

父类方法返回子类实例:PHP延迟静态绑定