zoukankan      html  css  js  c++  java
  • PHP5中__call、__get、__set、__clone、__sleep、__wakeup的用法

    __construct()__destruct()__call()__callStatic()__get()__set()__isset()__unset()__sleep()__wakeup()__toString()__invoke()__set_state()和 __clone() 等方法在 PHP 中被称为"魔术方法"(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

    PHP4中已经有了重载的语法来建立对于外部对象模型的映射,就像Java和COM那样. PHP5带来了强大的面向对象重载,允许程序员建立自定义的行为来访问属性和调用方法,php5加入了如下的内部特征 

    __construct(); 初始化--构造函数

    __destruct();     卸载--析构函数

    __get();       __get方法可以用来捕获一个对象中不存在的变量和方法

    __set();       __set方法可以用来捕获和按参数修改一个对象中不存在的变量和方法

    __call();       调用不存在的类的函数的时候得处理方法

    __clone();     copy对象用clone $obj;

    __sleep();     串行化的时候用

    __wakeup();     反串行化的时候用

    重载可以通过__get, __set, and __call几个特殊方法来进行. 当Zend引擎试图访问一个成员并没有找到时,PHP将会调用这些方法.

    在例6.14中,__get和__set代替所有对属性变量数组的访问. 如果必要,你可以实现任何类型你想要的过滤. 例如,脚本可以禁止设置属性值, 在开始时用一定的前缀或包含一定类型的值.

    __call方法说明了你如何调用未经定义的方法. 你调用未定义方法时,方法名和方法接收的参数将会传给__call方法, PHP传递__call的值返回给未定义的方法.

    __get()__set()__isset() 和 __unset() 参考:

    http://www.cnblogs.com/youxin/p/3256264.html

    方法重载:

    public mixed __call ( string $name , array $arguments )
    public static mixed __callStatic ( string $name , array $arguments )

    在对象中调用一个不可访问方法时,__call() 会被调用。

    用静态方式中调用一个不可访问方法时,__callStatic() 会被调用。

    $name 参数是要调用的方法名称。$arguments 参数是一个枚举数组,包含着要传递给方法 $name 的参数。

    <?php
    class MethodTest 
    {
        public function __call($name, $arguments) 
        {
            // 注意: $name 的值区分大小写
            echo "Calling object method '$name' "
                 . implode(', ', $arguments). "
    ";
        }
    
        /**  PHP 5.3.0之后版本  */
        public static function __callStatic($name, $arguments) 
        {
            // 注意: $name 的值区分大小写
            echo "Calling static method '$name' "
                 . implode(', ', $arguments). "
    ";
        }
    }
    
    $obj = new MethodTest;
    $obj->runTest('in object context');
    
    MethodTest::runTest('in static context');  // PHP 5.3.0之后版本
    ?>
    以上例程会输出:
    Calling object method 'runTest' in object context
    Calling static method 'runTest' in static context

    clone使用:

    对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。

    $copy_of_object = clone $object; 会自动调用__clone()方法。
    当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。

    php对象的浅克隆与深克隆:
    <?php
    class Test1 {
        public $num1 = 0;
        //包含的对象
        public $obj2;
    
        public function __construct() {
            $this->obj2 = new Test2;
        }
    }
    
    class Test2 {
        public $num2 = 0;
    }
    
    $obj1 = new Test1;
    
    /*
    PHP对象复制可以通过clone关键字来完成,当对象被复制后,
    PHP5会对对象的所有属性执行一个浅复制(shallow copy)。
    所有的引用属性仍然会是一个指向原来的变量的引用。
    */
    $obj = clone $obj1;
    
    $obj1->num1 = 1;
    $obj1->obj2->num2 = 1;
    
    var_dump($obj->num1, $obj->obj2->num2); #结果返回0和1
    //由此看出,此处执行了一个浅复制,只复制了基本属性,对象属性仍为指向原有变量的一个引用。

    深度clone:

    <?php
    class Test1 {
        public $num1 = 0;
        //包含的对象
        public $obj2;
    
        public function __construct() {
            $this->obj2 = new Test2;
        }
        
        public function __clone() {
            //实现深复制
            $this->obj2 = clone $this->obj2;
        }
    }
    
    class Test2 {
        public $num2 = 0;
    }
    
    $obj1 = new Test1;
    
    $obj = clone $obj1;
    
    $obj1->num1 = 1;
    $obj1->obj2->num2 = 1;
    
    var_dump($obj->num1, $obj->obj2->num2); #结果返回0和0
    //由此看出,此处执行了一个深复制,所有属性都创建了一个副本。

    上面的方法实现了魔法方法__clone,在这个方法中定义自己的深拷贝方式,这种写法比较麻烦,如果对象修改了,这个方法也得修改。事实上对成员进行深拷贝,可以采用将对象序列化后再还原的方式。这种写法可能性能上有所损失,但是确实最便捷的。PHP中,使用如下语句实现深拷贝:

    1
    $b2 = unserialize(serialize($b1));//序列化然后反序列化
     

    __sleep() 和 __wakeup()

    public array __sleep ( void )
    void __wakeup ( void )

    serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

    Note:

    __sleep() 不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。

    __sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。

    与之相反, unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup 方法,预先准备对象需要的资源。

    __wakeup() 经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作。

    Example #1 Sleep 和 wakeup

    <?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();
        }
    }
    ?>

    http://php.net/manual/zh/language.oop5.magic.php

    __toString() 方法用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

    例子6.16显示了如何用__sleep和__wakeup方法来串行化一个对象. Id属性是一个不打算保留在对象中的临时属性. __sleep方法保证在串行化的对象中不包含id属性. 当反串行化一个User对象,__wakeup方法建立id属性的新值. 这个例子被设计成自我保持. 在实际开发中,你可能发现包含资源(如图像或数据流)的对象需要这些方法
    
    Object serialization
    CODE: [Copy to clipboard]
    --------------------------------------------------------------------------------
    
    <?php 
    
    class User 
    { 
    public $name; 
    public $id; 
    
    function __construct() 
    { 
    //give user a unique ID 赋予一个不同的ID 
    $this->id = uniqid(); 
    } 
    
    function __sleep() 
    { 
    //do not serialize this->id 不串行化id 
    return(array("name")); 
    } 
    
    function __wakeup() 
    { 
    //give user a unique ID 
    $this->id = uniqid(); 
    } 
    } 
    
    //create object 建立一个对象 
    $u = new User; 
    $u->name = "Leon"; 
    
    //serialize it 串行化 注意不串行化id属性,id的值被抛弃 
    $s = serialize($u); 
    
    //unserialize it 反串行化 id被重新赋值 
    $u2 = unserialize($s); 
    
    //$u and $u2 have different IDs $u和$u2有不同的ID 
    print_r($u); 
    print_r($u2); 
    ?>
    _autoload()

    我们在平时调用一个类的时候,必须要先将该类所在的文件引入(include “xxx.php”),如果我们在一个页里调用的类很多,那么我们不得不使用许多的include “xxx.php”。显然这样很麻烦。

    __autoload()方法可以帮我们解决这个问题。

    比如我们将上面的那个Person类所在的文件定义为 Person_class.php  ,
    再新建一个php文件  test.php,编辑内容:

    function  __autoload($calssName)
    {
    include $className."_class.php";  //看到这也许你就明白了吧?哈哈
    }

    $p = new Person("mifan", 22);

    $p->say();

    这样执行该test.php页面就不会出现错误了。
    __autoload()方法是在生命不存在的类时调用的方法,它有一个string类型的参数是声明该不存在类的类名。
    当然,类文件的命名也是很有讲究的。最好是和类有关系,比如Person_class.php



  • 相关阅读:
    解决另一种方法解决Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-thtq7d55/frida/
    linux ubuntu pip3 list 出现警告
    Ubuntu安装curl报错:软件包有未满足的依赖关系: curl : 依赖: libcurl4 (= 7.58.0-2ubuntu3.10)
    安卓逆向手机环境搭建
    Proj THUDBFuzz Paper Reading: DIANE: Identifying Fuzzing Triggers in Apps to Generate Under-constrained Inputs for IoT Devices
    Proj THUDBFuzz Paper Reading: Automated Conformance Testing for JavaScript Engines via Deep Compiler Fuzzing
    Proj THUDBFuzz Paper Reading: Adaptive LL(*) Parsing: The Power of Dynamic Analysis
    Proj THUDBFuzz Paper Reading: Baloo: Measuring and Modeling the Performance Configurations of Distributed DBMS
    Proj IoTDBFuzz Paper Reading: Testing Java Exceptions: An Instrumentation Technique
    Proj IoTDBFuzz Paper Reading: VisFuzz: Understanding and Intervening Fuzzing with Interactive Visualization
  • 原文地址:https://www.cnblogs.com/youxin/p/3360164.html
Copyright © 2011-2022 走看看