登录 注册

登录

问题 [原创]一个综合例子揭示你在PHP的继承和重载中的不足: 延迟静态绑定.魔术函数.self.static.class.file.this.parent.操作域限

更多
2009年12月15日 13:29 - 2009年12月15日 16:07 #1 作者: 影雪
test.php
<?php
 
/**
To be supported 'static' , your PHP must be 5.3.0 or higher .
[原创]一个综合例子揭示你在PHP的继承和重载中的不足: 延迟静态绑定/魔术函数/self/static/class/file/this/parent/操作域限定符/
 
 
说明: 假设 类a放在 D:\usr\xampp\htdocs\test_inc.php
           类b放在 D:\usr\xampp\htdocs\test.php, 类b继承自类a
           请看自行演示, 并逐行仔细比较差别
 
*/
 
  //test.php
	require_once('test_inc.php');
 
	class b extends a {
 
		static $db ='b';
 
		function __construct(){
				( static::$db == 'a' ) ?  : print('我通过方法重载成了子类') . '<BR />';
			//这里print不能用echo代替,否则Parse error: syntax error, unexpected T_ECHO in D:\usr\xampp\htdocs\test.php on line 22
			echo 'parent:' . parent::$db . '<BR />';
	    $dd = (!isset($_GET['dd'])) ? : $_GET['dd'];
			echo '$_GET[\'dd\']: ' . $dd . '<BR />';
	    //PHP5.3.0 允许三目运算符的 ? 后面留空, 而 : 后面执行操作
		}
 
	}
 
	echo HR .'调用父类a' . HR;
	$aa = new a;
	$aa->ff();
	$aa->getName('bb','go','tt');
	echo BR;
 
	echo HR .'调用子类b' . HR;
	$bb = new b;
	$bb->ff();
	$bb->setName('bb');
	echo BR;
 
 
	echo HR .'拷贝对象' . HR;
  $cc = clone $bb;
	echo($cc);
	//print_r($cc);
	echo BR . BR; 
 
	echo HR .'串行化' . HR;
	echo '这是原来的我:<BR />'; 
  print_r($aa);
  echo '<BR />';
  $s1 = serialize($aa) ;
	print_r($s1);
	echo '<BR />';
	$s2 = unserialize($s1);
	print_r($s2);
	echo BR . BR; 
    
 
	echo HR .'销毁对象' . HR;
  unset($aa);	
	unset($bb);	
	unset($cc);
	unset($s1);
	unset($s2);
	//反串行化时会重新构造类a的实例,所以最后会多显示"我是类 :a 当删除一个对象或对象操作终止的时候会调用我", 而串行化时则无影响
	//事实上把上面的任何一个unset()函数注释掉对结果并无影响
	echo BR . BR; 	
 
 
?>


test_inc.php
<?php
 
	//test_inc.php
  error_reporting(E_ALL); // 报告所有错误
  define( 'BR' ,'
');
  define( 'HR' ,'<hr />');
  define( 'DS', DIRECTORY_SEPARATOR );
  defined( 'DS' ) or die('DS没有定义'); //die函数将在PHP6消失,最好用exit代替
  
  echo HR .'定义常量' . HR;
  echo 'BR: 我是HTML的换行标记' . BR .'哈哈' . BR;
  echo 'PHP_EOL: 我是系统默认换行符(windows:\r\n, linux和unix:\n,solaris(sun):\r): '. PHP_EOL .'哈哈'. BR;
  echo 'DS: 我是目录默认分隔符(windows:\, linux和unix:/): '. DS .'哈哈'. BR;
  echo BR;
  
  
	class a{
 
		static $db ='a';
		static $num = 0;
		var $id = 0; 
		var $usr = 'me';
		const dd = '类里定义常量dd用const,不用define' ;
		//define( 'dd' ,0); 会报错 Parse error: syntax error, unexpected T_STRING, expecting T_FUNCTION in D:\usr\xampp\htdocs\test_inc.php on line 22
 
 
		function __construct(){
			echo '我是父类,实例化时会自动调用我' . BR;
		}
		//构造函数
 
		function __destruct(){
		 	echo  '我是类 :' . get_called_class() . ' 当删除一个对象或对象操作终止的时候会调用我' . BR;
		}
		 //析构函数
 
	  function __clone(){
		 	echo '我复制了类'. get_called_class() . '的对象' . BR;
		}
    //将__construct()/__destruct()/__clone()用private标记,常用于单例模式,参见拙作: 《joomla里面的单例模式和纯静态类》
 
		public function __get($key){ //__get(),__set(),__call()等函数不能用 private和protected 标记,必须用public标记或者留空, 
				echo $key . " 不存在" . BR;
		}
		//当试图读取一个并不存在的属性的时候被调用。
 
  	public function __set($key,$value){
				echo '对'.$key . "附值" . $value . '失败' . BR;
		}
    //当试图向一个并不存在的属性写入值的时候被调用。
 
		function __call($Key, $Args){
				echo "您要调用的 {$Key} 方法不存在。你传入的参数是:" . print_r($Args, true) . BR;
		}
		//当试图调用一个对象并不存在的方法时,调用该方法。
 
		 public function __toString(){
			  return '打印我' . BR;
			  //echo或者print函数将自动调用该函数,print_r则不会
		 }
 
		function __sleep(){
			echo '我将被串行化:' . BR;
			return array('usr');
			//return array();
		}
 
		function __wakeup(){
			echo '我将被反串行化:' . BR;
			$this->id = 11 ;
		}
 
		function ff(){
 
      //echo 'this:' . $this->db . BR; 
			/*
			静态方法中访问普通属性只能通过self::来访问。如果改成$this会报错, 如:
			Notice: Undefined property: a::$db in D:\usr\xampp\htdocs\test_inc.php on line 73
			this:
 
			Notice: Undefined property: b::$db in D:\usr\xampp\htdocs\test_inc.php on line 73
			this:
 
      */
 
			echo 'self: ' . self::$db . BR;
			echo 'static: ' . static::$db . BR;
			//作为PHP 6 的新特性, 允许在操作域限定符::使用static关键字, 称为"延迟静态绑定",以方便父类中引用扩展类的最终状态,事实上在PHP5.3.0已经可以实现
	    echo 'class: ' . __CLASS__ . BR;
	    echo 'file: ' . __FILE__ . BR;
	    echo 'dirname: ' . dirname(__FILE__) . BR;
			echo 'call: ' . get_called_class() . BR;
			//PHP添加了get_called_class()函数,这允许检查继承的方法是从哪个派生类调用的。
 
 
      echo $this->dd;
      $this->dd = 1;
      echo self::dd . BR;
      $n1 = self::$num++;
      echo $n1 . BR;
      $n2 = ++self::$num;
      echo $n2 . BR;
 
		}
	}
 
?>


演示(忽略HR标记):

定义常量BR: 我是HTML的换行标记
哈哈
PHP_EOL: 我是系统默认换行符(windows:\r\n, linux和unix:\n,solaris(sun):\r): 哈哈
DS: 我是目录默认分隔符(windows:\, linux和unix:/): \哈哈

调用父类a我是父类,实例化时会自动调用我
self: a
static: a
class: a
file: D:\usr\xampp\htdocs\test_inc.php
dirname: D:\usr\xampp\htdocs
call: a
dd 不存在
对dd附值1失败
类里定义常量dd用const,不用define
0
2
您要调用的 getName 方法不存在。你传入的参数是:Array ( [0] => bb [1] => go [2] => tt )

调用子类b我通过方法重载成了子类
parent:a
$_GET: 1
self: a
static: b
class: a
file: D:\usr\xampp\htdocs\test_inc.php
dirname: D:\usr\xampp\htdocs
call: b
dd 不存在
对dd附值1失败
类里定义常量dd用const,不用define
2
4
您要调用的 setName 方法不存在。你传入的参数是:Array ( [0] => bb )

拷贝对象我复制了类b的对象
打印我


串行化这是原来的我:
a Object ( [id] => 0 [usr] => me )
我将被串行化:
O:1:"a":1:{s:3:"usr";s:2:"me";}
我将被反串行化:
a Object ( [id] => 11 [usr] => me )

销毁对象

我是类 :a 当删除一个对象或对象操作终止的时候会调用我
我是类 :b 当删除一个对象或对象操作终止的时候会调用我
我是类 :b 当删除一个对象或对象操作终止的时候会调用我
我是类 :a 当删除一个对象或对象操作终止的时候会调用我


路漫漫而修远兮,吾将上下而求索 [本人开发的免费网赚程序  www.shadowsnow.cn/GetForFree/index.asp ]

登录 或者   注册一个会员帐号 来参与讨论

更多
2009年12月15日 13:37 #2 作者: 影雪

登录 或者   注册一个会员帐号 来参与讨论