PHP5中__call、__get、__set、__clone、__sleep、__wakeup的用法

时间:2023-03-09 09:38:58
PHP5中__call、__get、__set、__clone、__sleep、__wakeup的用法

__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

方法重载:

public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )

在对象中调用一个不可访问方法时,__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()

public array __sleep ( void )
void __wakeup ( void )

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