魔术方法
Posted 一阙梅曲香素笺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了魔术方法相关的知识,希望对你有一定的参考价值。
特征,系统自定义的函数方法,都以__开头,自动被调用,可被继承,不可以自己定义,不能被static修饰除了__callStatic()
__construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __toString(), __invoke(), __set_state(), __clone() 和 __debugInfo() 等方法在 php 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。
PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。
__toString()
public string __toString ( void )
__toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。
示例1
<?php // Declare a simple class class TestClass { public $foo ; public function __construct ( $foo ) { $this -> foo = $foo ; } public function __toString () { return $this -> foo ; } } $class = new TestClass ( \'Hello\' ); echo $class ; ?>
以上例程会输出:
Hello
需要指出的是在 PHP 5.2.0 之前,__toString() 方法只有在直接使用于 echo 或 print 时才能生效。PHP 5.2.0 之后,则可以在任何字符串环境生效(例如通过 printf() ,使用 %s 修饰符),但不能用于非字符串环境(如使用 %d 修饰符)。自 PHP 5.2.0 起,如果将一个未定义 __toString() 方法的对象转换为字符串,会产生 E_RECOVERABLE_ERROR 级别的错误。
方法重载
public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )
在对象中调用一个不可访问方法时,__call() 会被调用。
用静态方式中调用一个不可访问方法时,__callStatic() 会被调用。
$name 参数是要调用的方法名称。 $arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。
__call()和__callStatic()用法一样,只是__callStatic()的方法为静态方法
属性重载
public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )
在给不可访问属性赋值时,__set() 会被调用。
读取不可访问属性的值时,__get() 会被调用。
当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
当对不可访问属性调用 unset() 时,__unset() 会被调用。
参数 $name 是指要操作的变量名称。__set() 方法的 $value 参数指定了 $name 变量的值。
属性重载只能在对象中进行。在静态方法中,这些魔术方法将不会被调用。所以这些魔术方法都不能被 声明为 static。从 PHP 5.3.0 起, 将这些魔术方法定义为 static 会产生一个警告。
Note:
因为 PHP 处理赋值运算的方式,__set() 的返回值将被忽略。类似的, 在下面这样的链式赋值中,__get() 不会被调用:
$a = $obj->b = 8;
Note:
在除 isset() 外的其它语言结构中无法使用重载的属性,这意味着当对一个重载的属性使用 empty() 时,重载魔术方法将不会被调用。
为避开此限制,必须将重载属性赋值到本地变量再使用 empty() 。
复制
在多数情况下,我们并不需要完全复制一个对象来获得其中属性。但有一个情况下确实需要:如果你有一个 GTK 窗口对象,该对象持有窗口相关的资源。你可能会想复制一个新的窗口,保持所有属性与原来的窗口相同,但必须是一个新的对象(因为如果不是新的对象,那么一个窗口中的改变就会影响到另一个窗口)。还有一种情况:如果对象 A 中保存着对象 B 的引用,当你复制对象 A 时,你想其中使用的对象不再是对象 B 而是 B 的一个副本,那么你必须得到对象 A 的一个副本。
对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。
$copy_of_object = clone $object;
当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。
void __clone ( void )
当复制完成时,如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,可用于修改属性的值(如果有必要的话)。
class City{ protected $name; private $area; function __construct($name, $area){ $this->name = $name; $this->area = $area; } /** * __get魔术方法,它是在外部访问该类中不能直接访问的属性时自动被调用 * 魔术方法都有其默认的定义格式,不能随意的更改 * 魔术方法不能被添加static静态的修饰符 * __get魔术方法必须有一个返回值 * @param $name 它对应的是类中的被声明的属性的名称,格式为字符串 */ function __get($name){ // echo \'我被调用了:\'.$name; if(isset($this->$name)){ return $this->$name; }else{ return null; } } /** * __set魔术方法,在给类中无法直接访问的属性赋值时自动调用 * @param $name 被赋值的类中的属性名称,字符串格式 * @param $value 被赋予的值 */ function __set($name, $value){ // echo \'我被调用了:\'.$name.\'===\'.$value; /* * property_exists 检测类或者对象中是否包含指定名称的属性 */ if(property_exists($this, $name)){ $this->$name = $value; }else{ echo \'类中没有对应的属性:\'.$name.\'<br>\'; } } function __isset($name){ if(property_exists($this, $name)){ return isset($this->$name); } } function __unset($name){ // echo \'需要销毁的属性:\'.$name; if(property_exists($this, $name)){ $this->$name = null; }else{ unset($this->$name); } } /** * __toString魔术方法,当使用字符串的方式来输出类的对象时被自动调用 * 它要求必须返回一个字符串结果 */ function __toString(){ return \'<br>城市名称:\'.$this->name.\',面积:\'.$this->area; } /** * __clone魔术方法,当类的对象被克隆时自动被调用 * 默认的克隆时浅克隆模式 * 该方法可以实现克隆时修改某些属性的值 */ function __clone(){ echo \'<br>调用了clone的魔术方法<br>\'; $this->area = \'3333平方公里\'; } } $city = new City(\'成都\', \'3000平方公里\'); //__clone() //$city2 = clone $city; //var_dump($city); //echo \'<br>\'; //var_dump($city2); //echo \'<br>\'; //__toString() //var_dump($city); //echo \'<br>\'; //print_r($city); //echo \'<br>\'; //print $city; //echo $city; //__call() //$city->test(); //$city->test1(\'哈哈哈哈\'); //$city->test2(100,200); // get() //echo \'名称:\'.$city->name.\'<br>\'; //echo \'面积:\'.$city->area.\'<br>\'; //echo \'人口:\'.$city->people.\'<br>\'; //echo \'<br>\'; //set() //$city->name = \'重庆\'; ////$city->people = \'15000000\'; //unset() //unset($city->name); //echo \'名称:\'.$city->name.\'<br>\'; //echo \'面积:\'.$city->area.\'<br>\'; //echo \'人口:\'.$city->people.\'<br>\'; //echo \'<br>\'; //var_dump($city); //根据$test是否有值使用isset //$test = false; //if(isset($test)){ echo \'OK\';} //判断是否有people这个变量 //if(isset($city->people)){ // echo \'====有值====\'; //}else{ // echo \'====没有获取到值====\'; //}
以上是关于魔术方法的主要内容,如果未能解决你的问题,请参考以下文章