魔术方法是PHP面向对象中特有的特性。它们在特定的情况下被触发,都是以双下划线开头,你可以把它们理解为钩子,利用魔术方法可以轻松实现PHP面向对象中重载(Overloading即动态创建类属性和方法)。
魔术方法很多还是成对出现的,以下列出目前PHP中所有的魔术方法:
1、__construct()与__destruct
__construct(),类的构造函数。在使用 new关键字使用类实例化一个对象时自动执行。
__destruct(),类的析构函数。在对象被销毁(unset或PHP执行结束)时自动执行,通常用于释放对象占用的第三方资源(如:数据库)。
2、__call()与__callStatic()
__call(),在对象中调用一个不可访问方法时调用。
class Person{
function __call($funName, $arguments)
{
echo "你所调用的函数:" . $funName . "不存在。\n\r" ; // 输出调用不存在的方法名
echo "参数为:\n\r";
print_r($arguments); // 输出调用不存在的方法时的参数列表
}
}
$Person = new Person();
$Person->eat("小明", "苹果");
以上例程会输出:
你所调用的函数:eat不存在。
参数为:
Array
(
[0] => 小明
[1] => 苹果
)
__callStatic(),用静态方式中调用一个不可访问方法时调用。
public static function __callStatic($funName, $arguments){
//...
}
3、__get()与__set()
当对一个对象的未定义的属性,进行“取值”时,此时会自动调用类中预先定义好的魔术方法__get()。
class Person{
private $name;
private $age;
function __construct($name="", $age=1){
$this->name = $name;
$this->age = $age;
}
public function __get($propertyName){
return $this->$propertyName;
}
}
$Person = new Person("小明", 50);
echo "姓名:" . $Person->name . "\n\r";
echo "年龄:" . $Person->age . "\n\r";
以上例程会输出:
姓名:小明
年龄:50
__set(),当对一个对象的未定义的属性,进行“赋值”时,此时会自动调用类中预先定义好的魔术方法__set()。
class Person{
private $name;
private $age;
public function __set($property, $value) {
if ($property=="age"){
if ($value > 150 || $value < 0) {
return;
}
}
$this->$property = $value;
}
}
$Person=new Person();
$Person->name = "小红"; //赋值成功。如果没有__set(),则出错。
$Person->age = 16; //赋值成功
$Person->age = 160; //160是一个非法值,赋值失效
4、__isset()与__unset()
__isset(),当对不可访问属性调用isset()或empty()时调用。
__unset(),当对不可访问属性调用unset()时被调用。
5、__sleep() 和 __wakeup()
__sleep(),执行serialize()时,先会调用这个函数;__wakeup(),执行unserialize()时,先会调用这个函数。
__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
__wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。
class Person{
public $sex;
public $name;
public $age;
public function __construct($name="", $age=25, $sex='男'){
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
public function __sleep() {
echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>";
$this->name = base64_encode($this->name);
return array('name', 'age'); // 这里必须返回一个数值,里边的元素表示返回的属
性名称
}
public function __wakeup() {
echo "当在类外部使用unserialize()时会调用这里的__wakeup()方法<br>";
$this->age = 30;
$this->sex = '女';
// 这里不需要返回数组
}
}
$person = new Person('小明'); // 初始赋值
$a = serialize($person);
var_dump($a);
$b = unserialize($a);
var_dump($b);
以上例程会输出:
当在类外部使用serialize()时会调用这里的__sleep()方法
/var/www/html/demo28.php:29:string 'O:6:"Person":2:{s:4:"name";s:8:"5bCP5piO";s:3:"age";i:25;}' (length=58)
当在类外部使用unserialize()时会调用这里的__wakeup()方法
/var/www/html/demo28.php:31:
object(Person)[2]
public 'sex' => string '女' (length=3)
public 'name' => string '5bCP5piO' (length=8)
public 'age' => int 30
官方例子:
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();
}
}
6、__toString()
__toString() 方法用于一个类被当成字符串时应怎样回应。
例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。
class TestClass{
public $foo = __CLASS__;
public function __toString() {
return $this->foo;
}
}
$class = new TestClass();
echo $class;
以上例程会输出:
TestClass
7、__invoke()
当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
class CallableClass {
function __invoke($x) {
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
以上例程会输出:
int(5)
bool(true)
8、__set_state()
__set_state(),调用var_export()导出类时,此静态方法会被调用。
class A{
public $var1;
public $var2;
public static function __set_state($an_array){
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));
var_dump($b);
以上例程会输出:
object(A)#2 (2) {
["var1"]=>
int(5)
["var2"]=>
string(3) "foo"
}
9、__clone()
在克隆(clone)对象时自动执行。
class C {
public function __clone() {
echo '正在克隆。。。';
}
}
$a = new C();
$b = clone $a;
以上例程会输出:
正在克隆。。。
10、__autoload()
__autoload(),尝试加载未定义的类。
function __autoload($className) {
$filePath = "project/class/{$className}.php";
if (is_readable($filePath)) {
require($filePath);
}
}
随着PHP版本的更新,该函数已经不建议使用,取而代之的是spl_auto_register()函数。
11、__debugInfo()
__debugInfo(),打印所需调试信息。
class C {
private $prop = 'test';
public function __debugInfo() {
return [
'data1' => $this->prop,
];
}
}
var_dump(new C());
以上例程会输出:
class C#1 (1) {
public $data1 =>
string(4) "test"
}