标签:
引子:
1 <?php 2 //值传递 3 $a=10; 4 $b=$a; //将变量a的值取出复制一份赋给变量b 5 $b=20; 6 echo $a; //10 7 8 //引用传递 9 $a=10; 10 $b=&$a; //为变量a起个别名b 11 $b=20; 12 echo $a; //20 13 ?>
由引子程序可以看到,当使用"="号时是值传递,两个变量相对独立,改变其中一个,另一个不会发生影响;当在变量前加上"&"符时,变成引用传递,相当于取别名,根本是还是同一个东西。但是当变量属于对象类型时,使用"="号时就变成了引用传递(资源类型也是),想达到"值传递"的效果,就可以使用克隆技术(只能用在对象类型)。
一、克隆
在PHP中可以根据现有的对象克隆出一个完全一样的对象,克隆以后,原来和副本两个对象完全独立、互不干扰。在PHP5中使用clone关键字克隆对象。
1 <?php 2 class Person {} 3 $p1=new Person(); //创建一个对象 4 $p2=$p1; //这不是复制对象,而是为对象多复制一个访问该对象的引用 5 $p3=clone $p1; //克隆(复制)一个对象的副本 6 7 var_dump($p1); //object(Person)[1] 8 var_dump($p2); //object(Person)[1] $p2和$p1是同一个对象 9 var_dump($p3); //object(Person)[2] 10 ?>
魔术方法"__clone()":该方法是在对象克隆时自动调用的,所以就可以通过此方法对克隆后的副本重新初始化。__clone()方法不需要任何参数,该方法中自动包含$this对象的引用,$this是副本对象的引用。
通过克隆技术我们可以方便的得到一个类型的对象,但是当此对象中包括资源或者子对象时又如何呢?
1 <?php 2 //测试 3 $f = new File("./a.txt"); 4 echo $f->read()."<br/>"; //aaaaaaaaaaa 5 echo $f->read()."<br/>"; //bbbbbbbbbbb 6 echo $f->read()."<br/>"; //ccccccccccc 7 8 $f2 = clone $f; 9 //unset($f); 10 echo $f2->read()."<br/>"; //ddddddddddd 11 12 var_dump($f); //object(File)[1]private ‘filename‘ => string ‘./a.txt‘ (length=7)private ‘link‘ => resource(3, stream) 13 var_dump($f2); //object(File)[2]private ‘filename‘ => string ‘./a.txt‘ (length=7)private ‘link‘ => resource(3, stream) 14 15 16 //自定义一个文件读取类 17 class File 18 { 19 private $filename; 20 private $link=null; 21 22 public function __construct($filename) 23 { 24 $this->filename = $filename; 25 $this->link = fopen($this->filename,"r"); 26 } 27 28 public function __destruct() 29 { 30 if($this->link != null){ 31 @fclose($this->link); 32 } 33 } 34 //魔术方法 35 /* public function __clone() 36 { 37 $this->link = fopen($this->filename,"r"); 38 }*/ 39 40 public function read() 41 { 42 return fgets($this->link); 43 } 44 45 } 46 ?>
当对象中包括资源或者子对象时,克隆并不能完全实现对象$f和对象$f2完全相对独立!!
当打开魔术方法__clone()此时var_dump()结果呢?
object(File)[1]private ‘filename‘ => string ‘./a.txt‘ (length=7)private ‘link‘ => resource(3, stream)
object(File)[1]private ‘filename‘ => string ‘./a.txt‘ (length=7)private ‘link‘ => resource(4, stream)
可以看到,link属性的资源号是不同的,此时对象$f和$f2完全相对独立。
二、魔术方法:__tostring()方法
当直接输出一个对象时,会尝试调用当前对象的__toString()方法,若没有则报错。
注意:__toString()魔术方法必须返回一个字串值。
1 <?php 2 class Stu 3 { 4 private $name="zhangsan"; 5 private $age=20; 6 7 public function __toString() 8 { 9 return $this->name.":".$this->age; 10 } 11 } 12 13 $s = new Stu(); 14 echo $s; 15 ?>
三、魔术方法:__call方法
如果尝试调用一个不存在的方法,则会调用此方法。需要两个参数:第一个参数是调用不存在方法时,接收这个方法的名称字符串;而第二个参数则以数组的形式传递到__call()方法的第二个参数中。
1 <?php 2 class A 3 { 4 public function fun1() 5 { 6 echo "fun1()....<br/>"; 7 } 8 public function fun2() 9 { 10 echo "fun2()....<br/>"; 11 } 12 public function __call($method,$params) 13 { 14 echo "你调用的{$method}方法不存在!参数: "; 15 print_r($params); 16 echo "<br/>"; 17 } 18 } 19 20 $a = new A(); 21 $a->fun1(); //fun1().... 22 $a->fun2(); //fun2().... 23 $a->fun3(100,200); //你调用的fun3方法不存在!参数: Array ( [0] => 100 [1] => 200 ) 24 $a->add("aa","bb","cc");//你调用的add方法不存在!参数: Array ( [0] => aa [1] => bb [2] => cc ) 25 ?>
四、自动加载类
当你尝试使用一个PHP没有组织到的类时,它会寻找一个名为__autoload()的全局函数(不是在类中声明的函数)如果存在这个函数,PHP会用一个参数来调用它,参数即类的名称。
1 <?php 2 //当实例化使用一个不存在的类时,此函数会自动调用,并将类传入, 3 function __autoload($classname) 4 { 5 //拼装文件 6 $fname = $classname.".PHP"; 7 if(file_exists($fname)){ 8 require($fname); 9 } 10 } 11 12 //测试学生类 13 14 //require("./Stu.php"); 15 16 17 $stu = new Stu("王五",23); 18 echo $stu; //王五:23 19 ?>
五、对象串行化(在对象持久化存储、和传输中使用)
对象也是一种在内存中存储的数据类型,它的寿命通常随着该对象的程序终止而终止。而对象通过写出描述自己状态的数值来记录自己,这个过程称为对象的串行化(Serialization):
a.对象需要在网络中传输时,将对象串行化成二进制字符串后再网络中传输;
b.对象需要持久保存时,将对象串行化后写入文件或数据库中。
serialize() -- 串行化
unserialize() -- 反串行化
php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。
unserialize()函数能够重新把字符串变回php原来的值。
序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
由于串行化就像克隆一样,虽然对象被串行化但是对象内的资源或子对象是不能被串行化的。
魔术方法:
__sleep():是执行串行化时自动调用的方法,目的是实现资源类型的属性实关闭操作
注意:sleep方法需要返回一个数组,其中数组中的值是串行化时要保留的属性名
__wakeup():是在执行反串行化时自动调用的方法,目的是实现资源属性的打开(sleep方法关闭的资源)
1 <?php 2 //串行化和反串行化中的魔术方法__sleep() __wakeup() 3 $f = new File("a.txt"); 4 5 $s = serialize($f); 6 7 echo $s; 8 9 $ob = unserialize($s); 10 11 echo $ob->read()."<br/>"; 12 echo $ob->read()."<br/>"; 13 echo $ob->read()."<br/>"; 14 15 16 //自定义一个文件读取类 17 class File 18 { 19 private $filename; 20 private $link=null; 21 22 public function __construct($filename) 23 { 24 $this->filename = $filename; 25 $this->link = fopen($this->filename,"r"); 26 } 27 28 public function __destruct() 29 { 30 if($this->link != null){ 31 @fclose($this->link); 32 } 33 } 34 35 //当此对象串行化时会自动调用此方法 36 public function __sleep() 37 { 38 return array("filename"); //返回需要保留的字段名(串行化时) 39 } 40 41 //当此对象反串行化时会自动调用此方法 42 public function __wakeup() 43 { 44 $this->link = fopen($this->filename,"r"); 45 } 46 47 public function read() 48 { 49 return fgets($this->link); 50 } 51 52 } 53 ?>
六、类型约束
类型约束可以使用的类型是:数组或对象。
若指定的一个类名,那么可传入本类及子类的对象进去。
可以使用的约束类型:(复合类型)数组array,类名、抽象类名、接口名
1 <?php 2 //类型约束:目前支持的为数组和对象 3 4 //此函的参数必须为数组类型 5 function fun(array $a){ 6 echo "数组长度:".count($a)."<br/>"; 7 } 8 9 fun([10,20,30,40]); 10 fun([10,20,30,40,50]); 11 //fun("aaaaaaaaaa"); //参数必须为一个数组 12 13 14 class A{} 15 class B extends A{} 16 class C{} 17 demo(new A()); 18 demo(new B()); 19 demo(new C()); //此处不可以,参数非法 20 21 //此函数的参数类型必须为A类的对象,或子类对象 22 function demo(A $ob) 23 { 24 echo "正常调用<br/>"; 25 } 26 ?>
七、对象连贯操作
1 <?php 2 //对象的连贯操作 3 4 class Demo 5 { 6 private $a = array(); 7 8 public function put($v) 9 { 10 $this->a[] = $v; 11 return $this; 12 } 13 14 public function __toString() 15 { 16 return implode(",",$this->a); 17 } 18 } 19 //测试 20 $d = new Demo(); 21 $d->put("aaa"); 22 $d->put("bbb"); 23 $d->put("ccc"); 24 echo $d; //aaa,bbb,ccc 25 26 $dd = new Demo(); 27 echo $dd->put("1111")->put("2222")->put("3333"); //1111,2222,3333
标签:
原文地址:http://www.cnblogs.com/yexiang520/p/5661993.html