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经典的给图片加水印程序
Dec 06 PHP
php获取mysql数据库中的所有表名的代码
Apr 23 PHP
通过PHP current函数获取未知字符键名数组第一个元素的值
Jun 24 PHP
PHP入门经历和学习过程分享
Apr 11 PHP
浅谈discuz密码加密的方式
May 22 PHP
php递归遍历删除文件的方法
Apr 17 PHP
curl 出现错误的调试方法(必看)
Feb 13 PHP
PHP使用数组实现矩阵数学运算的方法示例
May 29 PHP
php表单文件iframe异步上传实例讲解
Jul 26 PHP
Thinkphp5 自定义上传文件名的实现方法
Jul 23 PHP
gearman中worker常驻后台,导致MySQL server has gone away的解决方法
Feb 27 PHP
php远程请求CURL案例(爬虫、保存登录状态)
Apr 01 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
4月1日重磅发布!《星际争霸II》6.0.0版本更新
2020/04/09 星际争霸
PHP中使用FFMPEG获取视频缩略图和视频总时长实例
2014/05/04 PHP
YII框架中使用memcache的方法详解
2017/08/02 PHP
详解json在php中的应用
2018/09/30 PHP
跨浏览器开发经验总结(四) 怎么写入剪贴板
2010/05/13 Javascript
jquery实现微博文字输入框 输入时显示输入字数 效果实现
2013/07/12 Javascript
JS动态显示表格上下frame的方法
2015/03/31 Javascript
javascript实现在指定元素中垂直水平居中
2015/09/13 Javascript
基于jQuery下拉选择框插件支持单选多选功能代码
2016/06/07 Javascript
深入理解JS正则表达式---分组
2016/07/18 Javascript
Bootstrap源码解读网格系统(3)
2016/12/22 Javascript
数组Array的一些方法(总结)
2017/02/17 Javascript
socket.io学习教程之基本应用(二)
2017/04/29 Javascript
node使用UEditor富文本编辑器的方法实例
2017/07/11 Javascript
webpack配置导致字体图标无法显示的解决方法
2018/03/06 Javascript
js+canvas实现两张图片合并成一张图片的方法
2019/11/01 Javascript
three.js利用卷积法如何实现物体描边效果
2019/11/27 Javascript
JS数组的高级使用方法示例小结
2020/03/14 Javascript
[00:12]DAC2018 Miracle-站上中单舞台,他能否再写奇迹?
2018/04/06 DOTA
Python中endswith()函数的基本使用
2015/04/07 Python
Python下的subprocess模块的入门指引
2015/04/16 Python
详细讲解Python中的文件I/O操作
2015/05/24 Python
python实现批量下载新浪博客的方法
2015/06/15 Python
Django中的Signal代码详解
2018/02/05 Python
python面试题之列表声明实例分析
2019/07/08 Python
Html5 new XMLHttpRequest()监听附件上传进度
2021/01/14 HTML / CSS
材料采购员岗位职责
2013/12/17 职场文书
25岁生日感言
2014/01/13 职场文书
预备党员转正考核材料
2014/06/03 职场文书
副总经理任命书
2014/06/05 职场文书
春季运动会开幕词
2015/01/28 职场文书
2015小学语文教师个人工作总结
2015/05/20 职场文书
2015年试用期工作总结范文
2015/05/28 职场文书
试用期转正工作总结2015
2015/05/28 职场文书
2016年清明节期间群众祭祀活动工作总结
2016/04/01 职场文书
PHP设计模式(观察者模式)
2021/07/07 PHP