魔术方法
特征,系统自定义的函数方法,都以__开头,自动被调用,可被继承,不可以自己定义,不能被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 '====没有获取到值===='; //}