目录
从php5以后的版本,类就可以使用魔术方法了。PHP规定以两个下划线开头的方法都保留为魔术方法,所以建议大家函数名最好不用__开 头,除非是为了重载已有的魔术方法。
目前php已有的魔术方法有
- __construct
- __destruct
- __call
- __get
- __set
- __isset
- __unset
- __sleep
- __wakeup
- __toString
- __set_state
- __clone
__construct 和 __destruct
__construct和__destruct是类的构造函数和析构函数,这个大家经常会用到,相信大家都很熟悉,这里就不多说了。
__sleep和__wakeup
__sleep和__wakeup是序列化类的时候调用的。当序列化对象时,php将试图在序列动作之前调用该对象的成员函数__sleep(), 当使用unserialize() 恢复对象时, 将调用__wakeup()。
__toString
__toString是对象被转为string时调用的必须有返回值即:return xxx ; 否则报错,例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?php class Str { private $str; public function __construct($str) { $this->str = $str; } public function __toString() { return $this->str; } } $class = new Str('Hello'); echo $class; // 这里对象被转为了string,所以调用了__toString ?> |
上例将输出 Hello
__set_state
__set_state是当用var_export()来导出类的时候调用的,这个魔术函数只有一个参数,这个参数是一个数组,用来指定 export的时候得到的属性。一般很少用到。
__call, __get和__set
__call, __get和__set 这三个魔术方法是最常用的,当调用类中不存在的方法时就会调用__call,而__get和__set则是访问和设置类不存在的成员变量时调用的。
这三个的函数原型如下:
1 2 3 |
mixed __call(string $name, array $arguments) void __set(string $name, mixed $value) mixed __get(string $name) |
__call的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php class Caller { public function __call( $method , $args ) { echo "Method $method called:/n" ; print_r($args ); } } $foo = new Caller(); $foo ->test(1, 2); ?> |
上例将输出:
Method test called:
Array
(
[0] => 1
[1] => 2
)
__get 和 __set 的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?php class a { public $c = 0; public $arr = array(); public function __set($k, $v) { echo $k . "/n"; echo $v . "/n"; $this->arr[$k] = $v; } public function __get($k) { echo "The value of $k is " . $this->arr[$k]; } } $a = new a; $a->b = 1; // 成员变量b不存在,所以会调用__set $a->c = 2; // 成员变量c是存在的,所以不调用__set,无任何输出 $d = $a->b; // 成员变量b不存在,所以会调用__get ?> |
上例将输出:
b
1
The value of b is 1
__isset和__unset
__isset和__unset这两个与__get和__set其实原理是差不多的,他们的原型如下:
1 2 |
bool __isset(string $name) void __unset(string $name) |
举个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<?php class a { public $c = 3; public $arr = array ( 'a' => 1, 'b' => 2); public function __isset( $k ) { return isset( $this ->arr[ $k ]); } public function __unset( $k ) { unset($this ->arr[ $k ]); } } $a = new a; var_dump(isset($a ->a)); // 成员变量a不存在,所以调用__isset,返回true var_dump(isset($a ->c)); // 成员变量c是存在的,没有调用__isset,同样返回true unset($a ->b); // 成员变量b不存在,调用__unset var_dump($a ); ?> |
上例将输出:
bool(true)
bool(true)
object(a)#1 (2) {
[“c”]=>int(3)
[“arr”]=>array(1) {
[“a”]=>int(1)
}
}
__clone
类复制(clone)的时候,如果有定义__clone这个魔术方法就会调用它。
举例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php class a { public function __clone() { echo "object cloned" ; } } $a = new a; $b = $a ; // $b只是$a的引用, 不是克隆,所以不调用__clone,没任何输出。 $c = clone $a ; // 调用了__clone,将输出 object cloned ?> |
上例将输出:
object cloned
参考: http://php.net/manual/zh/language.oop5.magic.php
PHP的魔术常量
定义: 以两个_开头和结尾的常量为魔术常量
注意: 魔术常量不区分大小写
1 2 3 4 5 6 |
<?php $file1 = __FILE__; $file2 = __file__; var_dump($file1); var_dump($file2); ?> |
结果是:
string(36) “F:\Apache\www\temp\php_demo\temp.php”
string(36) “F:\Apache\www\temp\php_demo\temp.php”
_LINE_
文件中的当前行号。
_FILE_
文件的完整路径和文件名。如果用在被包含文件中,则返回被包含的文件名。自 PHP 4.0.2 起,FILE 总是包含一个绝对路径(如果是符号连接,则是解析后的绝对路径),而在此之前的版本有时会包含一个相对路径。
_DIR_
文件所在的目录。如果用在被包括文件中,则返回被包括的文件所在的目录。它等价于 dirname(FILE)。除非是根目录,否则目录中名不包括末尾的斜杠。(PHP 5.3.0中新增)
_FUNCTION_
函数名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该函数被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。
_CLASS_
类的名称(PHP 4.3.0 新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。在 PHP 4 中该值总是小写字母的。类名包括其被声明的作用区域(例如 Foo\Bar)。注意自 PHP 5.4 起 CLASS 对 trait 也起作用。当用在 trait 方法中时,CLASS 是调用 trait 方法的类的名字。
_NAMESPACE_
当前命名空间的名称(区分大小写)。此常量是在编译时定义的(PHP 5.3.0 新增)。
_TRAIT_
Trait 的名字(PHP 5.4.0 新加)。自 PHP 5.4 起此常量返回 trait 被定义时的名字(区分大小写)。Trait 名包括其被声明的作用区域(例如 Foo\Bar)。
_METHOD_
类的方法名(PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。
参考: http://php.net/manual/zh/language.constants.predefined.php