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 相关文章推荐
在PHP里得到前天和昨天的日期的代码
Aug 16 PHP
php生成随机密码的三种方法小结
Sep 04 PHP
PHP5 的对象赋值机制介绍
Aug 02 PHP
PHP中将字符串转化为整数(int) intval() printf() 性能测试
Mar 20 PHP
PHP代码审核的详细介绍
Jun 13 PHP
ThinkPHP的URL重写问题
Jun 22 PHP
php获取url参数方法总结
Nov 13 PHP
php字符串截取函数用法分析
Nov 25 PHP
php中mail函数发送邮件失败的解决方法
Dec 24 PHP
php模拟服务器实现autoindex效果的方法
Mar 10 PHP
PHP概率计算函数汇总
Sep 13 PHP
详解PHP中的外观模式facade pattern
Feb 05 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
PHP批量生成缩略图的代码
2008/07/19 PHP
php下实现在指定目录搜索指定类型文件的函数
2008/10/03 PHP
php access 数据连接与读取保存编辑数据的实现代码
2010/05/12 PHP
PHP中全面阻止SQL注入式攻击分析小结
2012/01/30 PHP
PHP中iconv函数转码时截断字符问题的解决方法
2015/01/21 PHP
使用Thinkphp框架开发移动端接口
2015/08/05 PHP
深入理解php printf() 输出格式化的字符串
2016/05/23 PHP
php数组函数array_walk用法示例
2016/05/26 PHP
完美解决thinkphp唯一索引重复时出错的问题
2017/03/31 PHP
PHP基于递归算法解决兔子生兔子问题
2018/05/11 PHP
使用mini-define实现前端代码的模块化管理
2014/12/25 Javascript
jquery实现标签支持图文排列带上下箭头按钮的选项卡
2015/03/14 Javascript
JS实现简单路由器功能的方法
2015/05/27 Javascript
jQuery动画效果图片轮播特效
2016/01/12 Javascript
javascript入门之window对象【新手必看】
2016/11/22 Javascript
jQuery布局组件EasyUI Layout使用方法详解
2017/02/28 Javascript
vue.js开发环境搭建教程
2017/05/04 Javascript
在bootstrap中实现轮播图实例代码
2017/06/11 Javascript
js实现canvas图片与img图片的相互转换的示例
2017/08/31 Javascript
vue2.0设置proxyTable使用axios进行跨域请求的方法
2017/10/19 Javascript
JS+HTML5 canvas绘制验证码示例
2018/12/05 Javascript
React路由鉴权的实现方法
2019/09/05 Javascript
[05:31]DOTA2英雄梦之声_第04期_光之守卫
2014/06/23 DOTA
利用python 更新ssh 远程代码 操作远程服务器的实现代码
2018/02/08 Python
spark: RDD与DataFrame之间的相互转换方法
2018/06/07 Python
Python爬虫将爬取的图片写入world文档的方法
2018/11/07 Python
pytorch 实现查看网络中的参数
2020/01/06 Python
Python3 pywin32模块安装的详细步骤
2020/05/26 Python
Pytorch 图像变换函数集合小结
2021/02/01 Python
纯CSS3实现鼠标滑过按钮动画第二节
2020/07/16 HTML / CSS
西班牙太阳镜品牌:Hawkers
2018/03/11 全球购物
英国皇家造币厂:The Royal Mint
2018/10/05 全球购物
魅力教师事迹材料
2014/01/10 职场文书
中学生国旗下讲话稿
2014/04/26 职场文书
幼儿园家长安全责任书
2014/07/22 职场文书
python关于集合的知识案例详解
2021/05/30 Python