专栏首页宣言(Siam)博客PHP类,魔术方法

PHP类,魔术方法

以下方法在 PHP 中被称为魔术方法(Magic methods)

__construct()
__destruct()
__call()
__callStatic()
__get()
__set()
__isset()
__unset()
__sleep()
__wakeup()
__toString()
__invoke()
__set_state()
__clone()
__debugInfo()

在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

下面介绍每个方法的作用

__construct

构造函数,在实例化类的时候会隐式调用该方法,可以接收传参。如:

class A{
    public function __construct($size) {
        $this->maxSize = $size; // 做一些初始化设置等等
        echo $this->maxSize;
    }
}

new A(3);

如果有一个类B继承了上面的类A ,如

class B extends A{
    public function __construct($size) {
        echo "hello";
    }
}

new B(3);

在此例子中,不会设置和输出maxSize属性,只会输出hello。

因为在子类重写构造方法时,需要显式调用父类构造函数 parent::__construct()

注意

如果在A类的构造函数,不是写为public,而是private,则无法被子类继承使用。

__destruct

析构函数,当类被手动销毁,或者脚本结束时,gc回收触发。可以执行一些后置操作,比如删除临时目录下的文件。

注意

  • 哪怕脚本调用exit(),die() 类的析构函数也会被执行
  • 如果在析构函数中调用exit() 则该函数内部的逻辑后续不再执行
public __destruct()
{
    echo 1;
    exit();
    echo 2;// 不会输出
}
  • 与构造函数相同,子类继承后需要显式调用父类的析构函数
  • 试图在析构函数(在脚本终止时被调用)中抛出一个异常会导致致命错误。

__call

当调用一个对象中的不能用的方法的时候就会执行这个函数。有两个参数:

function __call($function_name, $args)

测试

class A{
    public function __call($funcname, $args){
        var_dump($funcname);
        var_dump($args);
    }
}

$a = new A();
$a->one();
$a->tow('一个参数');

// 以下是输出

/*
string(3) "one"
array(0) {
}
string(3) "tow"
array(1) {
  [0]=>
  string(12) "一个参数"
}
string(5) "three"
array(2) {
  [0]=>
  string(12) "一个参数"
  [1]=>
  string(12) "两个参数"
}
*/

__callStatic

跟__call一样,但是该函数触发的是调用的静态方法。

A::test();

__get

读取不可访问属性的值时,__get() 会被调用。

猜想:在thinkphp框架的ORM中,关联模型

先在Orders模型中设置大概如下的方法

// 本模型的user ,代表要关联Users模型的一个数据,本模型的u_id = Users模型的id
public function user()
{
    return $this->belongTo('Users', 'u_id', 'id');
}

当在程序中调用,因为本身的Orders模型没有该属性,所以会尝试是否有设置该关系的方法,有则调用,然后返回Users的信息。

$orders = Orders::get(1);
var_dump(orders->user);

__set

在给不可访问属性赋值时,__set() 会被调用。

__isset

当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。

__unset

当对不可访问属性调用 unset() 时,__unset() 会被调用。

__sleep

__wakeup

这两个魔术方法是 类的序列化 使用的,后续会有一篇专门的文章讲解。

__toString

__toString() 方法用于一个类被当成字符串时应怎样回应。

比如,在我们接入微信支付的时候,经常需要把参数排序、拼接成url格式

我们完全可以定义一个类,然后在toString魔术方法中,写明排序、转换为url格式的操作。

// 伪代码

$params = new SiamWechatParams();
$params->appid = '1';
$params->total_fee = 200;

// http请求
Curl::send(self::url, $params->__toString());

// 其他地方直接输出,不手动显式调用
echo $params;

__invoke

当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。

class A
{
    function __invoke($params) {
        var_dump($params);
    }
}
$obj = new A();
$obj(5);
var_dump(is_callable($obj));

__set_state

自 PHP 5.1.0 起当调用 var_export() 导出类时,此静态 方法会被调用。

__clone

当对象复制完成时调用

__debugInfo

当调用var_dump函数时候,定义需要显示的属性列表

如果没有在对象上定义该方法,那么将显示所有公共、受保护和私有属性。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Layui模块化,改造传统jquery扩展为layui模块

    在我使用jquery扩展,拖拽组件的时候,因为使用的布局模板有些冲突,导致无法使用扩展,所以才会解决之后写下这篇文章。

    宣言言言
  • EasySwoole安装,包含所有组件

    宣言言言
  • PHP设置Redis储存Session,自定义session驱动

    我们在之前的文章已经讲到了session是将数据储存在本地文件中,并且将session_id返回给客户端(浏览器会储存在cookies里)。

    宣言言言
  • Dubbo剖析-服务消费端异步调用

    前面我们讲解的无论是正常调用还是泛化调用也好,都是进行同步调用的,也就是服务消费方发起一个远程调用后,调用线程要被阻塞挂起,直到服务提供方返回。本节来讲解下异步...

    加多
  • 宜信开源|调用链系列(1):解读UAVStack中的贪吃蛇

    对于分布式在线服务,一个请求需要经过多个系统中多个模块,可能多达上百台机器的协作才能完成单次请求。这种场景下单靠人力无法掌握整个请求中各个阶段的性能开销,更无法...

    宜信技术学院
  • JS 调用栈机制与 ES6 尾调用优化介绍

    调用栈的英文名叫做Call Stack,大家或多或少是有听过的,但是对于js调用栈的工作方式以及如何在工作中利用这一特性,大部分人可能没有进行过更深入的研究,这...

    OBKoro1
  • js 调用栈机制与ES6尾调用优化介绍

    本文中提到的链接,因为微信的限制,没有显示出来,查看文中链接,需要点击最下方的阅读原文链接

    OBKoro1
  • 快速学习-EVM指令集

    cwl_java
  • RPC原理及实现

    1 简介 RPC 的主要功能目标是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。为实现该目标,RPC 框架需提供一种透明...

    用户1263954
  • 求取一份极致的简单:全链路跟踪中间件探索之路

    公司内部的业务系统有近千个,基本上很少有比较孤立的;尤其外部系统,即便用户在页面上一个很普通的操作,后台也需要少则几个多则几十个服务协同完成。以前我们定位调用链...

    李海彬

扫码关注云+社区

领取腾讯云代金券