PHP中有很多以两个下划线开头的方法,如以前介绍过的__construct(), __destruct(), __clone(),这些方法被称为魔术方法。
魔术方法不用自己创建。
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(),__wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。
1.__set()和__get()方法
这两个方法是为在类和他们的父类中没有声明的属性而设计的(这里的没有声明包括当使用对象调用时,访问控制为proteced, private的属性(即没有权限访问的属性))
__get( $property ) 当调用一个未定义的属性(读取不可访问的属性)时访问此方法。这个方法用来获取私有成员属性值的,有一个参数,参数传入你要获取的成员属性的名称,返回获取的属性值,这个方法不用我们手工的去调用,因为我们也可以把这个方法做成私有的方法,是在直接获取私有属性的时候对象自动调用的。因为私有属性已经被封装上了,是不能直接获取值的(比如:“echo $p1->name”这样直接获取是错误的),但是如果你在类里面加上了这个方法,在使用“echo $p1->name”这样的语句直接获取值的时候就会自动调用__get($property_name)方法,将属性name传给参数$property_name,通过这个方法的内部执行,返回我们传入的私有属性的值。如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。
__set( $property, $value ) 给一个未定义的属性(不可访问的属性)赋值时调用。当程序试图写入一个不存在或不可见的成员变量时,PHP就会执行__set()方法,该方法包含两个参数,分别表示变量名和变量值,两个参数不可省略,没有返回值。这个方法同样不用我们手工去调用,它也可以做成私有的,是在直接设置私有属性值的时候自动调用的,同样属性私有的已经被封装上了,如果没有__set()这个方法,是不允许的,比如:$this->name=‘zhangsan’, 这样会出错,但是如果你在类里面加上了__set($property_name, $value)这个方法,在直接给私有属性赋值的时候,就会自动调用它,把属性比如name传给$property_name, 把要赋的值“zhangsan”传给$value,通过这个方法的执行,达到赋值的目的。如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。
注意:如果希望PHP调用这些魔术方法,首先必须在类中进行定义,否则PHP不会执行未定义的魔术方法。
class SportObject { private $type = ' '; //私有变量$type public function getType(){ //声明魔术方法__get() return $this -> type; } private function __get($name){ if(isset($this ->$name)){ //判断变量是否被声明 echo '变量'.$name.'的值为:'.$this -> $name.'<br>'; } else{ echo '变量'.$name.'未定义,初始化为0<br>'; $this -> $name = 0; //如果未声明,对变量进行初始化 } } private function __set($name, $value){ //声明魔术方法__set() if(isset($this -> $name)){ //判断变量是否定义 $this -> $name = $value; echo '变量'.$name.'赋值为:'.$value.'<br>'; }else{ $this -> $name = $value; //如果未定义,继续对变量进行赋值 echo '变量'.$name.'被初始化为:'.$value.'<br>'; } } } $MyComputer = new SportObject(); $MyComputer -> type = 'DIY'; //给变量赋值 $MyComputer -> type; //调用变量$type //$MyComputer -> name = 'NAY'; //给变量赋值 $MyComputer -> name; //调用变量$name
输出:变量type赋值为:DIY
变量type的值为:DIY
变量name未定义,初始化为0
变量name被初始化为:0
例2:
class Person { //下面是人的成员属性, 都是封装的私有成员 private $name; //人的名子 private $sex; //人的性别 private $age; //人的年龄 //__get()方法用来获取私有属性 private function __get($property_name) { echo "在直接获取私有属性值的时候,自动调用了这个__get()方法<br>"; if (isset ($this-> $property_name)) { return ($this-> $property_name); } else { return (NULL); } } //__set()方法用来设置私有属性 private function __set($property_name, $value) { echo "在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值<br>"; $this-> $property_name = $value; } } $p1 = new Person(); //直接为私有属性赋值的操作,会自动调用__set()方法进行赋值 $p1->name = "张三"; $p1->sex = "男"; $p1->age = 20; //直接获取私有属性的值, 会自动调用__get()方法,返回成员属性的值 echo "姓名:" . $p1->name . "<br>"; echo "性别:" . $p1->sex . "<br>"; echo "年龄:" . $p1->age . "<br>";
输出:
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接获取私有属性值的时候,自动调用了这个__get()方法
姓名:张三
在直接获取私有属性值的时候,自动调用了这个__get()方法
性别:男
在直接获取私有属性值的时候,自动调用了这个__get()方法
年龄:20
2.__call()和__callStatic()方法
__call( $method, $arg_array ) 当调用一个不存在或不可见的(未定义的方法)成员方法时调用此方法,这里的未定义的方法包括没有权限访问的方法。PHP先调用__call()方法来存储方法名及其参数。__call()方法包含两个参数,即方法名和方法参数。其中,方法参数是以数组形式存在的。
在对象中调用一个不可访问方法时,__call() 会被调用。
用静态方式中调用一个不可访问方法时,__callStatic() 会被调用。
$name 参数是要调用的方法名称。$arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。
PHP 确实加强了对 __callStatic() 方法的定义;它必须是公共的,并且必须被声明为静态的。同样,__call() 魔术方法必须被定义为公共的,所有其他魔术方法都必须如此。
class SportObject { public function myDream(){ echo '调用的方法存在,直接执行此方法。<p>'; } public function __call($method, $parameter) { echo '如果方法不存在,则执行__call()方法。<br>'; echo '方法名为:'.$method.'<br>'; echo '参数有:'; var_dump($parameter); } } $MyLife = new SportObject(); $MyLife -> myDream(); //调用存在的方法myDream() $MyLife -> mDream('how','what','why'); //调用存在的方法mDream()
输出:
调用的方法存在,直接执行此方法。
如果方法不存在,则执行__call()方法。
方法名为:mDream
参数有:array(3) { [0]=> string(3) "how" [1]=> string(4) "what" [2]=> string(3) "why" }
3.__sleep()和__wakeup()方法
PHP使用serialize()函数可以实现序列化对象。就是将对象中的变量全部保存下来,对象中的类则只保存类名。使用serialize()函数时,如果实例化的对象包含 __sleep()方法,则先会执行该方法。可以清除对象并返回一个包含该对象中所有变量的数组。使用__sleep()方法的目的是关闭对象可能具有类似数据库连接等善后工作。
unserialize()函数可以重新还原一个被seriaize()函数序列化的对象,__wakeup()方法则是恢复在序列化可能丢失的数据库连接及相关工作。
__sleep 串行化的时候用
__wakeup 反串行化的时候调用
serialize() 检查类中是否有魔术名称 __sleep 的函数。如果这样,该函数将在任何序列化之前运行。它可以清除对象并应该返回一个包含有该对象中应被序列化的所有变量名的数组。
使用 __sleep 的目的是关闭对象可能具有的任何数据库连接,提交等待中的数据或进行类似的清除任务。此外,如果有非常大的对象而并不需要完全储存下来时此函数也很有用。
相反地,unserialize() 检查具有魔术名称 __wakeup 的函数的存在。如果存在,此函数可以重建对象可能具有的任何资源。
使用 __wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。
class SportObject{ private $type = 'DIY'; public function getType(){ return $this -> type; } public function __sleep(){ //声明魔术方法__sleep() echo '使用serialize()函数将对象保存起来,可以存放到文本文件、数据库等地方<br>'; return $this; } public function __wakeup(){ //声明魔术方法__wakeup() echo '当需要该数据时,使用unserialize()函数对已序列化的字符串进行操作,将其转换回对象<br>'; } } $myBook = new SportObject(); $i = serialize($myBook); //序列化对象 echo '序列化后的字符串:'.$i.'<br>';//输出字符串$i $reBook = unserialize($i); //将字符串$i重新转换为对象$reBook echo '还原后的成员变量:'.$reBook -> getType(); //调用新对象$reBook的getType()方法
输出:
使用serialize()函数将对象保存起来,可以存放到文本文件、数据库等地方
序列化后的字符串:O:12:"SportObject3":1:{s:3:"DIY";N;}
当需要该数据时,使用unserialize()函数对已序列化的字符串进行操作,将其转换回对象
还原后的成员变量:DIY
4.__toString()方法
__toString方法在将一个对象转化成字符串时自动调用,比如使用echo或print输出对象时。
如果类没有实现此方法,则无法通过echo打印对象,否则会显示:Catchable fatal error: Object of class test could not be converted to string in
此方法必须返回一个字符串
在PHP 5.2.0之前,__toString方法只有结合使用echo() 或 print()时 才能生效。PHP 5.2.0之后,则可以在任何字符串环境生效(例如通过printf(),使用%s修饰符),但 不能用于非字符串环境(如使用%d修饰符)。从PHP 5.2.0,如果将一个未定义__toString方法的对象 转换为字符串,会报出一个E_RECOVERABLE_ERROR错误。
class SportObject{ private $type = 'DIY'; public function __toString(){ return $this -> type; //方法返回私有变量type的值} } $myComputer = new SportObject(); echo '对象$myComputer的值为:'; echo $myComputer; //输出对象$myComputer
输出:对象$myComputer的值为:DIY
5.__autoload()方法
__autoload()方法可以自动实例化需要使用的类。当程序要用到一个类,但该类还没有被实例化时,PHP将调用__autoload()方法,在制定的路径下自动查找和该类名称相同的文件。如果找到,程序则继续执行;否则,报告错误。
__autoload 函数,它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
注意: 在 __autoload 函数中抛出的异常不能被 catch 语句块捕获并导致致命错误。
<?php class SportObject{ private $cont; public function __construct($cont){ $this -> cont = $cont; } public function __toString(){ return $this -> cont; } } ?> function __autoload($class_name){ $class_path = $class_name.'.class.php'; if(file_exists($class_path)){ include_once($class_path); }else echo '类路径错误。'; } $myBook = new SportObject("江山代有人才出 各领风骚数百年"); echo $myBook;
输出:江山代有人才出 各领风骚数百年
6.__isset()和__unset()方法
__isset( $property ) 当在一个未定义的属性上调用isset()函数时调用此方法
__unset( $property ) 当在一个未定义的属性上调用unset()函数时调用此方法
与__get方法和__set方法相同,这里的没有声明包括当使用对象调用时,访问控制为proteced,private的属性(即没有权限访问的属性)
__isset()–在对类中属性或者非类中属性使用isset()方法的时候如果没有或者非公有属性,则自动执行__isset()的方法
__unset()–在对类中属性或者非类中属性使用unset()方法的时候如果没有或者非公有属性,则自动执行__unset()的方法
class Example { public $public; protected $protected; private $private; public function __construct(){ $this->public = 'pub'; $this->protected = 'pro'; $this->private = 'pri'; } public function __isset($var){ echo '这里通过__isset()方法查看属性名为 '.$var."\n"; } public function __unset($var){ echo '这里通过__unset()方法要销毁属性名为 '.$var."\n"; } } $exa = new Example; echo '<pre>'; var_dump(isset($exa->public)); echo "\n"; var_dump(isset($exa->protected)); echo "\n"; var_dump(isset($exa->private)); echo "\n"; var_dump(isset($exa->noVar)); echo "\n"; echo '<hr/>'; unset($exa->public); var_dump($exa); echo "\n"; unset($exa->protected); echo "\n"; unset($exa->private); echo "\n"; unset($exa->noVar); echo "\n";
结果如下:
bool(true)
这里通过__isset()方法查看属性名为 protected
bool(false)
这里通过__isset()方法查看属性名为 private
bool(false)
这里通过__isset()方法查看属性名为 noVar
bool(false)
7.__construct、__destruct
__construct 构造方法,当一个对象创建时调用此方法,使用此方法的好处是:可以使构造方法有一个独一无二的名称,无论它所在的类的名称是什么.这样你在改变类的名称时,就不需要改变构造方法的名称
__destruct 析构方法,PHP将在对象被销毁前(即从内存中清除前)调用这个方法
默认情况下,PHP仅仅释放对象属性所占用的内存并销毁对象相关的资源.
· 析构函数允许你在使用一个对象之后执行任意代码来清除内存.
· 当PHP决定你的脚本不再与对象相关时,析构函数将被调用.
· 在一个函数的命名空间内,这会发生在函数return的时候.
· 对于全局变量,这发生于脚本结束的时候.如果你想明确地销毁一个对象,你可以给指向该对象的变量分配任何其它值.通常将变量赋值勤为NULL或者调用unset.
8.__set_state
当调用var_export()时,这个静态 方法会被调用(自PHP 5.1.0起有效)。
本方法的唯一参数是一个数组,其中包含按array('property’ => value, …)格式排列的类属性。
9.__invoke
当尝试以调用函数的方式调用一个对象时,__invoke 方法会被自动调用。
PHP5.3.0以上版本有效
参考网址:
http://php.net/manual/zh/language.oop5.magic.php
转载请注明: ITTXX.CN--分享互联网 » php基础(十六)--类和对象之魔术方法
最后更新:2019-03-14 15:33:05