1、调用属性
1)、__get()、__set()
1:在php面向对象的编程中,总是把类的属性定义为private。但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属性。
2:类似于java中的javabean的操作,使用的方法也类似,只是不需要像javabean中那样,对每个字段进行set和get的操作。只需要加上两个魔术方法即可。这两个方法不是默认存在的,需要手工添加到类中,像构造方法(__construct())一样,在类中添加了才会存在。
例:
【注】
1:调用类的私有属性和成员
2:__set()方法必须有两个参数,返回值可有可无
__get()方法必须有一个参数,返回值可有可无。
2)、__isset()
1:__isset()方法是用来检测私有属性是否存在:
2:在外部直接用isset()方法检测类的私有属性是检测不到的,只有在类中加了魔术方法__isset(),才能在外部使用isset()方法检测到。
【注】:必须有一个参数,,返回值有
3)、__unset()
1:__unset()方法用来在类的外部删除类的私有属性
2:在外部直接使用 unset()方法也是不行的,因为是私有属性,所以也需要在类里面使用魔术方法__unset().
【注】:必须有一个参数,返回值无
2、调用方法
1)、__call()
1:为了避免要调用的方法不存在时产生错误,我们使用魔术方法__cal()来避免。
2:如果没有__call()魔术方法,直接在外面调没有定义的go()方法会报错。
__call()方法的存在,让外面不会因为没有定义的方法而抛出错误,程序会正常的执行下去。
【注】参数有2个(未定义方法名,参数【可以是数组】)
2)、__callStatic()
有了__callStatic(),当发现调用的静态方法不存在时,会自动调用这个魔术方法。程序不会报错。
【注】参数有2个(未定义方法名,参数【可以是数组】)
get_called_class()返回类名
3、__invoke()
把对象以函数的方式被调用的时候,invoke方法就会被自动调用
4、__toString()
当你想打印对象的时候,这个方法就会被自动调用。
参数:无,返回值:必须有。
5、__clone
1)、深拷贝与浅拷贝
对象复制存在两种形式:浅拷贝,深拷贝
浅拷贝:变量之间是地址传递的。地址上是一个值,大家共享这个值。
深拷贝:把变量值复制一份,然后再传递给另一个变量。变量之间是值传递的,
使用关键字clone ,就能完成深拷贝。而PHP默认的是浅拷贝
浅拷贝的例子:
深拷贝的例子:
因为浅拷贝是非常省内存的,所以PHP默认的是浅拷贝的。
2)、__clone()方法的使用
__clone()这个魔术方法会在使用clone关键字的时候自动调用。
【注】参数:无,返回值:不需要。
6、序列化
1)、serialize()与unserialize ()
serialize()把类实例化出的对象转化成字符串的过程返回字符串,此字符串包含了表示 value 的字节流,可以存储于任何地方。
unserialize ()还原已经序列化的对象。
3)、__sleep()
1:__sleep():过滤掉在对象串行化过程中不需要留下的成员属性
2:在程序执行前,serialize() 函数会首先检查是否存在一个魔术方法 __sleep.如果存在,__sleep()方法会先被调用, 然后才执行串行化(序列化)操作。
3:这个功能可以用于清理对象,并返回一个包含对象中所有变量名称的数组。如果该方法不返回任何内容,则NULL被序列化,导致 一个E_NOTICE错误。
<?php
class user {
public $name;
public $id;
function __construct() {
$this->id = uniqid();
//uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID。
}
function __sleep() { //返回需要序列化的成员属性。
return(array('name'));
}
}
$u = new user();
$u->name = "Leo";
$s = serialize($u); //id属性被抛弃,只序列化name属性。
print_r($s); //O:4:"user":1:{s:4:"name";s:3:"Leo";}
?>
【注】当一个对象被串行化,PHP会调用__sleep方法(如果存在的话),如果没有__sleep方法,PHP将保存所有属性。
4)、__wakeup()
1:__wakeup():经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
2:当反串行化一个User对象,__wakeup方法建立id属性的新值
<?php
class user {
public $name;
public $id;
function __construct() {
$this->id = 2;
}
function __sleep() { //返回需要序列化的成员属性。
//抛弃了id属性,并非抛弃,只是存在另一块内存中,只有__wakeup()方法才可唤醒
return(array('name'));
}
function __wakeup() {
//唤醒id 属性,并给id 重新赋值。
$this->id = 3;
}
}
$u = new user();
$u->name = "Leo";
$s = serialize($u); //id属性被抛弃,只序列化name属性。
$u2 = unserialize($s); //unserialize反串行化,id值被重新赋值
//对象u和u2有不同的id赋值
print_r($s);
print_r($u2);
/*打印结果:
user Object ( [name] => Leo [id] => 2 ) user Object ( [name] => Leo [id] => 3 )
?>
【注】
1:在反串行化一个对象时,PHP 会调用__wakeup方法(如果存在)。
2:这两个方法都不接受参数. __sleep方法必须返回一个数组,包含需要串行化的属性. PHP会抛弃其它属性的值.
【问题】
1:当序列化时__sleep()方法没有出现时,反序列化时__wakeup()方法存在可以吗?有什么用?
答案:可以存在,__sleep()不存在,PHP默认的把所有属性都序列化保存。而在反序列化时__wakeup()存在,依然会先执行,进行赋值或初始化操作。
<?php
class A {
public $b;
public $name;
}
class B extends A {
public $parent;
public function __wakeup() {
$this->parent->name;//给B的parent属性赋值为$name
}
}
$a = new A();
$a->name = "foo";
$a->b = new B();
$s = serialize($a);
$m = unserialize($s);
var_dump($m);exit;
/*因为反序列化时先执行 __wakeup(),而__wakeup()在B类中。
所以在B::__wakeup执行时, $a->name还没有被赋值,所以为NULL
*/
//object(A)#3 (2) { ["b"]=> object(B)#4 (3) { ["parent"]=> NULL ["b"]=> NULL ["name"]=> NULL } ["name"]=> string(3) "foo" }
//所以,一定要小心你定义类中变量的执行顺序。
?>