魔术方法
__clone()
php5中的对象模型是通过引用来调用对象的,但有时需要建立副本,改变原来对象时不希望影响到副本。在php 中可以使用对象克隆出一个完全一样的对象,克隆后,原本和克隆副本两个对象完全独立,互不干扰。使用clone关键字实现.
<?php
header('content-type:text/html;charset=utf-8');
class Person{
var $name;
var $sex;
var $age;
function __construct($name,$sex="男",$age=1){
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
function say(){
echo "我的姓名:".$this->name. " 性别:".$this->sex. ' 年龄:'.$this->age.'<br/>';
}
}
$p1=new Person('张三');
$p2=clone $p1;//克隆副本
$p1->say();
$p2->say();
//结果如下
我的姓名:张三 性别:男 年龄:1
我的姓名:张三 性别:男 年龄:1
上面通过clone关键克隆出来的一个完全一样的副本,两个对象完全独立。如果需要对克隆出来后的副本赋初值,可以在类中声明一个魔术方法“__clone”。该方法是在对象克隆时自动调用的,所以可以通过该方法对克隆后的副本赋初始值。该方法中自动包含$this和$that两个对象引用。其中$this表示对副本对象的引用,$that表示对原本对象的引用。
<?php
header('content-type:text/html;charset=utf-8');
class Person{
var $name;
var $sex;
var $age;
function __construct($name,$sex="男",$age=20){
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
function __clone(){
$this->name="我是".$this->name."副本";
$this->age=10;
}
function say(){
echo "我的姓名:".$this->name. " 性别:".$this->sex. ' 年龄:'.$this->age.'<br/>';
}
}
$p1=new Person('张三');
$p2=clone $p1;//自动调用__clone方法为副本赋初始值
$p1->say();
$p2->say();
//结果如下:
我的姓名:张三 性别:男 年龄:20
我的姓名:我是张三副本 性别:男 年龄:10
_tostring()
魔法方法__tostring()是快速获取对象的字符串表示的最快捷的方法,它是直接输入对象的引用时直接调用的方法。例如:$p=new Person 对象的引用,如果直接使用echo 输出$p,则会出错。如果在类中添加__tostring()方法,则直接输入对象的引用时不会出错,而是自动调用该方法,并输出方法中返回的字符串。所以在__tostring()方法中一定要有一个字符串作为返回值,通常在此方法中返回的字符串是使用对象中多个属性值连接而成的。
<?php
header('content-type:text/html;charset=utf-8');
class Myclass{
private $foo;
private $x;
function __construct($foo,$head){
$this->foo=$foo;
$this->head=$head;
}
function __tostring(){
//该方法必须有一个字符串作为返回值
return $this->foo." ".$this->head;
}
}
$obj=new Myclass("Hello",'world!');
echo $obj;//输入对象引用时自动调用__tostring()方法
//结果如下:
Hello world!
__call()
如果调用对象中不存在的方法,一定会出现系统错误,并退出程序不能继续执行。在php中,可以在类中添加一个魔法方法__call(),则调用对象中不存在的方法时就会自动调用该方法,并且程序会继续向下执行。所以我们可以接__call()方法提示用户,列如:提示该用户该方法不存在或者参数列表不存在。__call()方法需要两个参数,第一个参数是:调用不存在的方法时,接收这个方法名称的字符串,第二个参数是:参数列表则以数组的形式传递到__call()方法的。
<?php
header('content-type:text/html;charset=utf-8');
class Myclass{
function printfHello(){
echo "Hello";
}
function __call($functionName,$args){
echo "你所调用的函数".$functionName."(参数:";
print_r($args);
echo ")不存在<br/>";
}
}
$obj=new Myclass("Hello",'world!');
//当函数不存在时,自动调用__call()方法,并把方法名和参数列表传给该函数
$obj->myFun("one",2,"tree");
$obj->otherFun(8,9);
$obj->printfHello();
//结果如下:
你所调用的函数myFun(参数:Array ( [0] => one [1] => 2 [2] => tree ) )不存在
你所调用的函数otherFun(参数:Array ( [0] => 8 [1] => 9 ) )不存在
Hello
__autoload()
在面向对象中,如果我们使用一个未定义的类时,PHP会报一个致命的错误、一般我们用include包含一个类所在的源文件,如果一个页面需要使用多个类,就不得不在脚本页面开头编写一个长长的包含文件的列表,将本页面需要的类全部包含进来。这样处理不仅繁琐,而且容易出错。
PHP 中提供了类的自动加载功能,当你尝试使用一个PHP没有组织类的时,它会寻找一个__autoload()全局函数(不是在类中声明的函数),如果存在这个函数,PHP会用一个参数来调用它,参数即类名。
<?php
function __autoload($className){
//在方法中使用include包含类所在的文件
include(strtolower($className).".class.php");
}
$p1=new Test();//Test类不存在则会自动调用__autoload()函数,将类名作为参数传入。
对象串行化
对象也是一种在内存中存储的数据类型,它的寿命通常随着生成该对象的程序的终止而终止。有时候,可能需要将对象的状态保存下来,需要的时候在恢复。对象通过描述自己状态的数值来记录自己,这个过程称对象的序列化。串行化就是把整个对象转化成二进制字符串。以下两种情况必须把对象串行化:
一:对象需要在网络中传输时,将对象串行化成二进制后再网络中传输。
二:对象需要持久保存时,将对象串行化写入文件或数据库中。
使用serialize()函数来串行化一个对象,把对象转化成二进制。serialize()函数需要一个参数就是对象的引用名,返回值为一个对象被串行化的字符串。
使用unserialize()函数来反串行化一个对象,就是把对象串行化后的二进制字符串在转化为对象。该函数的参数serialize()函数的返回值,返回值当然是重新组织好的对象。
Person.class.php
<?php
header('content-type:text/html;charset=utf-8');
class Person{
var $name;
var $sex;
var $age;
function __construct($name,$sex="男",$age=20){
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
function say(){
echo "我的姓名:".$this->name. " 性别:".$this->sex. ' 年龄:'.$this->age.'<br/>';
}
}
serialize.php
<?php
header('content-type:text/html;charset=utf-8');
require "Person.class.php";
$person=new Person('张三','男',40);
$person_string=serialize($person);
file_put_contents("file.txt",$person_string);
//file.txt
O:6:"Person":3:{s:4:"name";s:6:"张三";s:3:"sex";s:3:"男";s:3:"age";i:40;}
unserialize.php
<?php
header('content-type:text/html;charset=utf-8');
require "Person.class.php";
$person_string=file_get_contents("file.txt");
$person=unserialize($person_string);
$person->say();
//结果如下:
我的姓名:张三 性别:男 年龄:40
在php5中还提供两个魔术方法 __sleep()和__wakeup()可以使用。在调用serialize()函数将对象串行化时,会自动调用__sleep()方法,用来将对象中的部分成员串行化。__sleep()函数不需要接受任何参数,但需要返回一个数组,在数组中包含需要串行化的属性。未被包含在数组中的属性将在串行化时被忽略。如果类中没有该方法,则对象中的所有属性都将被串行化。在调用unserialize()函数反串行化时,会自动调用__wakeup()方法,用来二进制串中重新组成一个对象时,为新对象中的成员属性重新初始化。
<?php
header('content-type:text/html;charset=utf-8');
class Person{
var $name;
var $sex;
var $age;
function __construct($name,$sex="男",$age=20){
$this->name=$name;
$this->sex=$sex;
$this->age=$age;
}
function say(){
echo "我的姓名:".$this->name. " 性别:".$this->sex. ' 年龄:'.$this->age.'<br/>';
}
function __sleep(){
$arr=array("name","age");
return $arr;
}
function __wakeup(){
$this->age=40;
}
}
$person=new Person("张三");
$person_string=serialize($person);
echo $person_string."<br>";
$person2=unserialize($person_string);
$person2->say();
//说明:其中成员属性$sex没有在数组中,没有被串行化,所有在反串行化时,组织成的对象将不会存在成员属性$sex
//结果如下:
O:6:"Person":2:{s:4:"name";s:6:"张三";s:3:"age";i:20;}
我的姓名:张三 性别: 年龄:40