php教程之魔术方法的使用示例(php魔术函数)


Posted in PHP onFebruary 12, 2014
/** PHP把所有以__(两个下划线)开头的类方法当成魔术方法。所以你定义自己的类方法时,不要以 __为前缀。 * */
// __toString、__set、__get__isset()、__unset()
/*
  The __toString method allows a class to decide how it will react when it is converted to a string.
  __set() is run when writing data to inaccessible members.
  __get() is utilized for reading data from inaccessible members.
  __isset() is triggered by calling isset() or empty() on inaccessible members.
  __unset() is invoked when unset() is used on inaccessible members.
 */
class TestClass {
    private $data = array();
    public $foo;
    public function __construct($foo) {
        $this->foo = $foo;
    }
    public function __toString() {
        return $this->foo;
    }
    public function __set($name, $value) {
        echo "__set, Setting '$name' to '$value'\n";
        $this->data[$name] = $value;
    }
    public function __get($name) {
        echo "__get, Getting '$name'\n";
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }
    }
    /** As of PHP 5.1.0 */
    public function __isset($name) {
        echo "__isset, Is '$name' set?\n";
        return isset($this->data[$name]);
    }
    /** As of PHP 5.1.0 */
    public function __unset($name) {
        echo "__unset, Unsetting '$name'\n";
        unset($this->data[$name]);
    }
}
$obj = new TestClass('Hello');
echo "__toString, $obj\n";
$obj->a = 1;
echo $obj->a . "\n\n";
var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n\n"; 
/**
  输出结果如下:
  __toString, Hello
  __set, Setting 'a' to '1'
  __get, Getting 'a'
  __isset, Is 'a' set?
  bool(true)
  __unset, Unsetting 'a'
  __isset, Is 'a' set?
  bool(false)
 **/
 
// __call  __callStatic
/*
  mixed __call ( string $name , array $arguments )
  mixed __callStatic ( string $name , array $arguments )
  __call() is triggered when invoking inaccessible methods in an object context.
  __callStatic() is triggered when invoking inaccessible methods in a static context.
  The $name argument is the name of the method being called.
  The $arguments argument is an enumerated array containing the parameters passed to the $name'ed method.
 */
class MethodTest {
    public function __call($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "__call, Calling object method '$name' " . implode(', ', $arguments) . "\n";
    }
    /** As of PHP 5.3.0 */
    public static function __callStatic($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "__callStatic, Calling static method '$name' " . implode(', ', $arguments) . "\n";
    }
}
$obj = new MethodTest;
$obj->runTest('in object context', 'param2', 'param3');
//MethodTest::runTest('in static context'); // As of PHP 5.3.0
echo "\n\n"; 
/**
 输出结果如下:
 __call, Calling object method 'runTest' in object context, param2, param3
  string(10) "__invoke: "
 */
 
// __invoke
/* 
  The __invoke method is called when a script tries to call an object as a function.
  Note: This feature is available since PHP 5.3.0.
*/
class CallableClass {
    function __invoke($x) {
        var_dump($x);
    }
}
$obj = new CallableClass;
//$obj(5);
var_dump('__invoke: ' . is_callable($obj));
echo "\n\n"; 
 
 
// __sleep  __wakeup
/*
  串行化serialize可以把变量包括对象,转化成连续bytes数据. 你可以将串行化后的变量存在一个文件里或在网络上传输. 
  然后再反串行化还原为原来的数据. 你在反串行化类的对象之前定义的类,PHP可以成功地存储其对象的属性和方法. 
  有时你可能需要一个对象在反串行化后立即执行. 为了这样的目的,PHP会自动寻找__sleep和__wakeup方法.
  当一个对象被串行化,PHP会调用__sleep方法(如果存在的话). 在反串行化一个对象后,PHP 会调用__wakeup方法. 
  这两个方法都不接受参数. __sleep方法必须返回一个数组,包含需要串行化的属性. PHP会抛弃其它属性的值. 
  如果没有__sleep方法,PHP将保存所有属性.下面的例子显示了如何用__sleep和__wakeup方法来串行化一个对象. 
  Id属性是一个不打算保留在对象中的临时属性. __sleep方法保证在串行化的对象中不包含id属性. 
  当反串行化一个User对象,__wakeup方法建立id属性的新值. 这个例子被设计成自我保持. 
  在实际开发中,你可能发现包含资源(如图像或数据流)的对象需要这些方法
 */
class User {
    public $name;
    public $id;
    function __construct() {
        //give user a unique ID 赋予一个差别 的ID
        $this->id = uniqid();
    }
    //__sleep返回值的类型是数组,数组中的值是不需要串型化的字段id
    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);
echo "__sleep, __wakeup, s: $s"; //unserialize it 反串行化 id被重新赋值
$u2 = unserialize($s); //$u and $u2 have different IDs $u和$u2有差别 的ID
print_r($u);
print_r($u2);
echo "\n\n"; 
/**
 输出结果如下:
  __sleep, __wakeup, s: O:4:"User":1:{s:4:"name";s:4:"Leon";}
  User Object
  (
  [name] => Leon
  [id] => 4db1b17640da1
  )
  User Object
  (
  [name] => Leon
  [id] => 4db1b17640dbc
  )
 */

// __set_state
/*
  This static method is called for classes exported by var_export() since PHP 5.1.0.
  The only parameter of this method is an array containing exported properties in the form array('property' => value, ...).
 */
class A {
    public $var1;
    public $var2;
    public static function __set_state($an_array) { // As of PHP 5.1.0
        //$an_array打印出来是数组,而不是调用时传递的对象
        print_r($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';
echo "__set_state:\n";
eval('$b = ' . var_export($a, true) . ';'); 
// $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));
var_dump($b);
echo "\n\n"; 
/**
  输出结果如下:
  __set_state:
  Array
  (
  [var1] => 5
  [var2] => foo
  )
  object(A)#5 (2) {
  ["var1"]=>
  int(5)
  ["var2"]=>
  string(3) "foo"
  }
 */
 
// __clone
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() {
        // Force a copy of this->object, otherwise
        // it will point to same object.
        $this->object1 = clone $this->object1;
    }
}
$obj = new MyCloneable();
$obj->object1 = new SubObject();
$obj->object2 = new SubObject();
$obj2 = clone $obj;
print("__clone, Original Object:\n");
print_r($obj);
print("__clone, Cloned Object:\n");
print_r($obj2);
echo "\n\n";
/**
 输出结果如下:
 __clone, Original Object:
  MyCloneable Object
  (
  [object1] => SubObject Object
  (
  [instance] => 1
  ) [object2] => SubObject Object
  (
  [instance] => 2
  ))
  __clone, Cloned Object:
  MyCloneable Object
  (
  [object1] => SubObject Object
  (
  [instance] => 3
  ) [object2] => SubObject Object
  (
  [instance] => 2
  )) 
 */
PHP 相关文章推荐
PHP4(windows版本)中的COM函数
Oct 09 PHP
discuz论坛 用户登录 后台程序代码
Nov 27 PHP
php设置静态内容缓存时间的方法
Dec 01 PHP
分享一则PHP定义函数代码
Feb 26 PHP
php获得网站访问统计信息类Compete API用法实例
Apr 02 PHP
分享50个提高PHP执行效率的技巧
Dec 26 PHP
Laravel5.1数据库连接、创建数据库、创建model及创建控制器的方法
Mar 29 PHP
一波PHP中cURL库的常见用法代码示例
May 06 PHP
php处理复杂xml数据示例
Jul 11 PHP
PHP写的简单数字验证码实例
May 23 PHP
PHP实现找出链表中环的入口节点
Jan 16 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
Nov 26 PHP
php-fpm配置详解
Feb 12 #PHP
PHP添加Xdebug扩展的方法
Feb 12 #PHP
php和jquery实现地图区域数据统计展示数据示例
Feb 12 #PHP
php中的路径问题与set_include_path使用介绍
Feb 11 #PHP
php 不使用js实现页面跳转
Feb 11 #PHP
简单的php中文转拼音的实现代码
Feb 11 #PHP
PHP字符串的递增和递减示例介绍
Feb 11 #PHP
You might like
ThinkPHP关联模型操作实例分析
2012/09/23 PHP
javascript面向对象之Javascript 继承
2010/05/04 Javascript
jquery鼠标滑过提示title具体实现代码
2013/08/06 Javascript
javascript 兼容各个浏览器的事件
2015/02/04 Javascript
详解javascript中的事件处理
2015/11/06 Javascript
动态加载js文件简单示例
2016/04/21 Javascript
jquery表单插件Autotab使用方法详解
2016/06/24 Javascript
gulp加批处理(.bat)实现ng多应用一键自动化构建
2017/02/16 Javascript
谈谈VUE种methods watch和compute的区别和联系
2017/08/01 Javascript
JavaScript正则表达式的贪婪匹配和非贪婪匹配
2017/09/05 Javascript
Angular实现搜索框及价格上下限功能
2018/01/19 Javascript
React中的render何时执行过程
2018/04/13 Javascript
angular 内存溢出的问题解决
2018/07/12 Javascript
vue中监听路由参数的变化及方法
2019/12/06 Javascript
jquery选择器和属性对象的操作实例分析
2020/01/10 jQuery
原生js实现弹窗消息动画
2020/11/20 Javascript
vue使用lodop打印控件实现浏览器兼容打印的方法
2021/02/07 Vue.js
Django中Forms的使用代码解析
2018/02/10 Python
python 读文件,然后转化为矩阵的实例
2018/04/23 Python
Python 调用 zabbix api的方法示例
2019/01/06 Python
使用Python3内置文档高效学习以及官方中文文档
2019/05/19 Python
keras实现多种分类网络的方式
2020/06/11 Python
Python2手动安装更新pip过程实例解析
2020/07/16 Python
Python使用内置函数setattr设置对象的属性值
2020/10/16 Python
python 高阶函数简单介绍
2021/02/19 Python
借助HTML5 Canvas API制作一个简单的猜字游戏
2016/03/25 HTML / CSS
澳大利亚领先的宠物用品商店:VetSupply
2017/09/08 全球购物
意大利网上书店:LaFeltrinelli
2020/06/12 全球购物
什么是Connection-oriented Protocol/Connectionless Protocol面向连接的协议/无连接协议
2012/09/06 面试题
客服端调用EJB对象的几个基本步骤
2012/01/15 面试题
请用Java实现列出某个目录下的所有文件
2013/09/23 面试题
优秀教师单行材料
2014/12/16 职场文书
2015年干部教育培训工作总结
2015/05/15 职场文书
HR必备:超全面的薪酬待遇管理方案!
2019/07/12 职场文书
python实现ROA算子边缘检测算法
2021/04/05 Python
vue实现同时设置多个倒计时
2021/05/20 Vue.js