PHP5中__call、__get、__set、__clone、__sleep、__wakeup的用法
2013-10-09 21:28 youxin 阅读(536) 评论(0) 编辑 收藏 举报__construct(),__destruct(),__call(),__callStatic(),__get(),__set(),__isset(),__unset(),__sleep(),__wakeup(),__toString(),__invoke(),__set_state()和 __clone() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
PHP4中已经有了重载的语法来建立对于外部对象模型的映射,就像Java和COM那样. PHP5带来了强大的面向对象重载,允许程序员建立自定义的行为来访问属性和调用方法,php5加入了如下的内部特征
__construct(); 初始化--构造函数
__destruct(); 卸载--析构函数
__get(); __get方法可以用来捕获一个对象中不存在的变量和方法
__set(); __set方法可以用来捕获和按参数修改一个对象中不存在的变量和方法
__call(); 调用不存在的类的函数的时候得处理方法
__clone(); copy对象用clone $obj;
__sleep(); 串行化的时候用
__wakeup(); 反串行化的时候用
重载可以通过__get, __set, and __call几个特殊方法来进行. 当Zend引擎试图访问一个成员并没有找到时,PHP将会调用这些方法.
在例6.14中,__get和__set代替所有对属性变量数组的访问. 如果必要,你可以实现任何类型你想要的过滤. 例如,脚本可以禁止设置属性值, 在开始时用一定的前缀或包含一定类型的值.
__call方法说明了你如何调用未经定义的方法. 你调用未定义方法时,方法名和方法接收的参数将会传给__call方法, PHP传递__call的值返回给未定义的方法.
__get(),__set(),__isset() 和 __unset() 参考:
http://www.cnblogs.com/youxin/p/3256264.html
方法重载:
在对象中调用一个不可访问方法时,__call() 会被调用。
用静态方式中调用一个不可访问方法时,__callStatic() 会被调用。
$name 参数是要调用的方法名称。$arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。
<?php class MethodTest { public function __call($name, $arguments) { // 注意: $name 的值区分大小写 echo "Calling object method '$name' " . implode(', ', $arguments). "\n"; } /** PHP 5.3.0之后版本 */ public static function __callStatic($name, $arguments) { // 注意: $name 的值区分大小写 echo "Calling static method '$name' " . implode(', ', $arguments). "\n"; } } $obj = new MethodTest; $obj->runTest('in object context'); MethodTest::runTest('in static context'); // PHP 5.3.0之后版本 ?> 以上例程会输出: Calling object method 'runTest' in object context Calling static method 'runTest' in static context
clone使用:
对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。
$copy_of_object = clone $object; 会自动调用__clone()方法。
当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。
php对象的浅克隆与深克隆:
<?php class Test1 { public $num1 = 0; //包含的对象 public $obj2; public function __construct() { $this->obj2 = new Test2; } } class Test2 { public $num2 = 0; } $obj1 = new Test1; /* PHP对象复制可以通过clone关键字来完成,当对象被复制后, PHP5会对对象的所有属性执行一个浅复制(shallow copy)。 所有的引用属性仍然会是一个指向原来的变量的引用。 */ $obj = clone $obj1; $obj1->num1 = 1; $obj1->obj2->num2 = 1; var_dump($obj->num1, $obj->obj2->num2); #结果返回0和1 //由此看出,此处执行了一个浅复制,只复制了基本属性,对象属性仍为指向原有变量的一个引用。
深度clone:
<?php class Test1 { public $num1 = 0; //包含的对象 public $obj2; public function __construct() { $this->obj2 = new Test2; } public function __clone() { //实现深复制 $this->obj2 = clone $this->obj2; } } class Test2 { public $num2 = 0; } $obj1 = new Test1; $obj = clone $obj1; $obj1->num1 = 1; $obj1->obj2->num2 = 1; var_dump($obj->num1, $obj->obj2->num2); #结果返回0和0 //由此看出,此处执行了一个深复制,所有属性都创建了一个副本。
上面的方法实现了魔法方法__clone,在这个方法中定义自己的深拷贝方式,这种写法比较麻烦,如果对象修改了,这个方法也得修改。事实上对成员进行深拷贝,可以采用将对象序列化后再还原的方式。这种写法可能性能上有所损失,但是确实最便捷的。PHP中,使用如下语句实现深拷贝:
1
|
$b2 = unserialize(serialize($b1)); //序列化然后反序列化 |
__sleep() 和 __wakeup()
serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL
被序列化,并产生一个 E_NOTICE
级别的错误。
Note:
__sleep() 不能返回父类的私有成员的名字。这样做会产生一个
E_NOTICE
级别的错误。可以用 Serializable 接口来替代。
__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
与之相反, unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。
__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
Example #1 Sleep 和 wakeup
<?php class Connection { protected $link; private $server, $username, $password, $db; public function __construct($server, $username, $password, $db) { $this->server = $server; $this->username = $username; $this->password = $password; $this->db = $db; $this->connect(); } private function connect() { $this->link = mysql_connect($this->server, $this->username, $this->password); mysql_select_db($this->db, $this->link); } public function __sleep() { return array('server', 'username', 'password', 'db'); } public function __wakeup() { $this->connect(); } } ?>
http://php.net/manual/zh/language.oop5.magic.php
__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR
级别的致命错误。
例子6.16显示了如何用__sleep和__wakeup方法来串行化一个对象. Id属性是一个不打算保留在对象中的临时属性. __sleep方法保证在串行化的对象中不包含id属性. 当反串行化一个User对象,__wakeup方法建立id属性的新值. 这个例子被设计成自我保持. 在实际开发中,你可能发现包含资源(如图像或数据流)的对象需要这些方法 Object serialization CODE: [Copy to clipboard] -------------------------------------------------------------------------------- <?php class User { public $name; public $id; function __construct() { //give user a unique ID 赋予一个不同的ID $this->id = uniqid(); } function __sleep() { //do not serialize this->id 不串行化id return(array("name")); } function __wakeup() { //give user a unique ID $this->id = uniqid(); } } //create object 建立一个对象 $u = new User; $u->name = "Leon"; //serialize it 串行化 注意不串行化id属性,id的值被抛弃 $s = serialize($u); //unserialize it 反串行化 id被重新赋值 $u2 = unserialize($s); //$u and $u2 have different IDs $u和$u2有不同的ID print_r($u); print_r($u2); ?>
_autoload()
我们在平时调用一个类的时候,必须要先将该类所在的文件引入(include “xxx.php”),如果我们在一个页里调用的类很多,那么我们不得不使用许多的include “xxx.php”。显然这样很麻烦。
__autoload()方法可以帮我们解决这个问题。
比如我们将上面的那个Person类所在的文件定义为 Person_class.php ,
再新建一个php文件 test.php,编辑内容:
function __autoload($calssName)
{
include $className."_class.php"; //看到这也许你就明白了吧?哈哈
}
$p = new Person("mifan", 22);
$p->say();
这样执行该test.php页面就不会出现错误了。
__autoload()方法是在生命不存在的类时调用的方法,它有一个string类型的参数是声明该不存在类的类名。
当然,类文件的命名也是很有讲究的。最好是和类有关系,比如Person_class.php