PHP的重载及魔术方法

首先你要知道什么是php的魔术方法,它不是变魔术的,如果你想学习变魔术来错地方了哦!

定义:PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __ 为前缀。

作用:利用模式方法可以轻松实现PHP面向对象中重载(Overloading即动态创建类属性和方法)

其实很多博客主已经写过这些方法了、、、但是我还是要说一遍。。谁让你来听了呢,码这么多字也不容易看完再走吧!

1.__construct,__destruct
__constuct构建对象的时被调用;
__destruct明确销毁对象或脚本结束时被调用;

class Foo {

    private $name;
    private $link;

    public function __construct($name) {
        $this->name = $name;
    }

    public function __destruct() {
        echo 'Destroying: ', $this->name, PHP_EOL;//PHP_EOL代表php的换行符
    }
}

打住,先安利一波重载的定义及使用方法:

定义:PHP所提供的"重载"(overloading)是指动态地"创建"类属性和方法。(我们是通过魔术方法(magic methods)来实现的)

作用:当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用。后面将使用"不可访问属性(inaccessible properties)"和"不可访问方法(inaccessible methods)"来称呼这些未定义或不可见的类属性或方法。

注意:所有的重载方法都必须被声明为 public

2.__get、__set、__isset、__unset、__call、__callStatic  //为啥放一起呢?


__set当给不可访问或不存在属性赋值时被调用
__get读取不可访问或不存在属性时被调用

__isset对不可访问或不存在的属性调用isset()或empty()时被调用
__unset对不可访问或不存在的属性进行unset时被调用

__call调用不可访问或不存在的方法时被调用
__callStatic调用不可访问或不存在的静态方法时被调用

Example #1 使用 __get()__set()__isset() 和 __unset() 进行属性重载

<?php
class PropertyTest {
     /**  被重载的数据保存在此  */
    private $data = array();

 
     /**  重载不能被用在已经定义的属性  */
    public $declared = 1;

     /**  只有从类外部访问这个属性时,重载才会发生 */
    private $hidden = 2;

    public function __set($name, $value) 
    {
        echo "Setting '$name' to '$value'
";
        $this->data[$name] = $value;
    }


    public function __get($name) 
    {
        echo "Getting '$name'
";
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }

        $trace = debug_backtrace();
        trigger_error(
            'Undefined property via __get(): ' . $name .
            ' in ' . $trace[0]['file'] .
            ' on line ' . $trace[0]['line'],
            E_USER_NOTICE);
        return null;
    }



    /**  PHP 5.1.0之后版本 */
    public function __isset($name) 
    {
        echo "Is '$name' set?
";
        return isset($this->data[$name]);
    }

    /**  PHP 5.1.0之后版本 */
    public function __unset($name) 
    {
        echo "Unsetting '$name'
";
        unset($this->data[$name]);
    }

    /**  非魔术方法  */
    public function getHidden() 
    {
        return $this->hidden;
    }
}


echo "<pre>
";

$obj = new PropertyTest;

$obj->a = 1;
echo $obj->a . "

";

var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "
";

echo $obj->declared . "

";

echo "Let's experiment with the private property named 'hidden':
";
echo "Privates are visible inside the class, so __get() not used...
";
echo $obj->getHidden() . "
";
echo "Privates not visible outside of class, so __get() is used...
";
echo $obj->hidden . "
";
?>

看完了吗?好好看!


5.__sleep,__wakeup
__sleep当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用

__wakeup当使用unserialize时被调用,可用于做些对象的初始化操作

<?php
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.__clone
进行对象clone时被调用,用来调整对象的克隆行为

<?php
class SubObject
{
    static $instances = 0;
    public $instance;

    public function __construct() {
        $this->instance = ++self::$instances;
    }

    public function __clone() {
        $this->instance = ++self::$instances;
    }
}

class MyCloneable
{
    public $object1;
    public $object2;

    function __clone()
    {
      
        // 强制复制一份this->object, 否则仍然指向同一个对象
        $this->object1 = clone $this->object1;
    }
}

$obj = new MyCloneable();

$obj->object1 = new SubObject();
$obj->object2 = new SubObject();

$obj2 = clone $obj;


print("Original Object:
");
print_r($obj);

print("Cloned Object:
");
print_r($obj2);

?>


7.__toString
当一个类被转换成字符串时被调用

<?php
class SubObject
{
    static $instances = 0;
    public $instance;

    public function __construct() {
        $this->instance = ++self::$instances;
    }

    public function __clone() {
        $this->instance = ++self::$instances;
    }
}

class MyCloneable
{
    public $object1;
    public $object2;

    function __clone()
    {
      
        // 强制复制一份this->object, 否则仍然指向同一个对象
        $this->object1 = clone $this->object1;
    }
}

$obj = new MyCloneable();

$obj->object1 = new SubObject();
$obj->object2 = new SubObject();

$obj2 = clone $obj;


print("Original Object:
");
print_r($obj);

print("Cloned Object:
");
print_r($obj2);

?>

8.__set_state
当调用var_export()导出类时,此静态方法被调用。用__set_state的返回值做为var_export的返回值。

<?php

class A
{
    public $var1;
    public $var2;

    public static function __set_state($an_array) // As of PHP 5.1.0
    {
        $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);

?>

enmmm,我知道你记不住的。。这么多谁记得住啊,好烦啊、、、别,这还没讲完呢,更多方法请参考PHP的官方文档:http://php.net/manual/zh/,别打我,你自己去看吧,毕竟好东西还是要众乐乐的!了;另外这些代码你最好再编译器中运行一边,不然看完你估计和没看一个样2333 ····  

作者原创、转载请注明出处

原文地址:https://www.cnblogs.com/ldw-blogs/p/7764969.html