沉睡的木乃伊:var_export() 与可解析字符串

news2024/11/25 20:37:18

文章目录

  • 参考
  • 环境
  • var_export()
      • 概念
      • 应用场景
          • 数据持久化
          • 调试
      • 函数 var_export()
  • 自定义类
      • __set_state() 魔术方法
      • 设置 __set_state 魔术方法的逻辑以复原对象
      • 注意事项
  • 通用内置空类 stdClass
      • stdClass
      • 对 __set_state() 的天然支持

参考

项目描述
搜索引擎BingGoogle
AI 大模型文心一言通义千问讯飞星火认知大模型ChatGPT
PHP 官方PHP Manual
PHP 官方language.oop5.magic.php
PHP 官方function.var-export.php

环境

项目描述
PHP5.5.05.6.87.0.07.2.57.4.98.0.08.2.9
PHP 编辑器PhpStorm 2023.1.1(专业版)

var_export()

概念

var_export() 是 PHP 中用于 将数据转换为合法的 PHP 可解析字符串的一个内置函数var_export() 函数的主要目的是生成一个字符串,该字符串包含了一个 数据及该数据所属的数据类型的表示,以便后续可以通过 eval() 函数重新恢复该数据。

应用场景

数据持久化

var_export()eval() 可以用于实现数据持久化,因为它们共同提供了一种 将数据结构序列化为字符串,然后在需要时重新创建该数据结构的方法。这个过程可以用于将数据保存在文件或数据库中,然后在以后重新加载和使用它。

调试

var_export() 生成的输出易于阅读,它以有效的 PHP 代码形式表示变量的 值和类型,使开发人员能够快速理解变量的内容。

函数 var_export()

函数 var_export() 的大致定义如下:

function var_export(     
	mixed $value,     
	bool $return = false 
): null|string

其中:

属性描述
$value该参数用于指定 需要被转化为合法的 PHP 可解析字符串的变量或数据
$return该参数用于指定 是否需要将转化结果作为函数的返回值进行返回。如果为 false(默认值),则转化结果将 直接输出至终端,至于函数的返回值将被设置为 NULL

举个栗子

<?php


$arr = [1, 2, 3, 4, 5];
print("数组:\n");
var_export($arr);

print("\n\n字符串:\n");
var_export("Hello World");

print("\n\n整型:\n");
var_export(1);

print("\n\n布尔型:\n");
$result = var_export(TRUE, true);
print($result);

print("\n\nPHP 提供的内置通用空类的实例化对象:\n");
var_export(new stdClass());

print("\n\n自定义空类的实例化对象:\n");
class MyClass {};
var_export(new MyClass());

print("\n\n资源类型:\n");
$fp = fopen('./path/to/file', 'r');
var_export($fp);

执行效果

数组:
array (
  0 => 1,
  1 => 2,
  2 => 3,
  3 => 4,
  4 => 5,
)

字符串:
'Hello World'

整型:
1

布尔型:
true

PHP 提供的内置通用空类的实例化对象:
(object) array(
)

自定义空类的实例化对象:
MyClass::__set_state(array(
))

资源类型:
NULL

自定义类

__set_state() 魔术方法

var_export() 函数在处理自定义对象时,会尝试将对象转化为形如

被处理对象所属的类::__set_state(array(
   '属性1' => '属性值1',
   '属性2' => '属性值2',
))

的字符串。在通过 eval() 函数复原对象时,字符串将被视为 PHP 代码进行执行,静态魔术方法 __set_state() 将被调用。属性与属性值组成的关联数组将被作为 __set_state() 方法的参数 用于规定复原对象的逻辑。若尝试通过 eval() 函数将一个未定义 __set_state() 方法的对象的可解析字符串还原为对象,则 PHP 将为此抛出 Fatal Error 异常。对此,请参考如下示例:

<?php


class MyClass
{
    public $name = "RedHeart";
    public $age = 18;
    public $nation = "China";
}

$indicate_text = var_export(new MyClass(), true);
print($indicate_text . "\n");

# 尝试通过 eval 将可解析字符串还原为对象
$result = eval('return ' . $indicate_text . ';');
print_r($result);

在上述示例代码中,为了将 $inidicate_text 的执行结果作为 eval 函数的返回值进行返回,我们将 $indicate_textreturn 语句进行拼接,又由于 eval() 函数的参数必须为 合法的可解析的 PHP 代码,我们又在 $indicate_text 的末尾拼接了 分号

执行效果

使用 eval() 函数将 var_export() 函数产生的可解析字符串复原为原始对象需要该对象的所属类实现了 __set_state() 魔术方法。否则,PHP 将抛出 Fatal Error 异常并立即终止。

MyClass::__set_state(array(
   'name' => 'RedHeart',
   'age' => 18,
   'nation' => 'China',
))
PHP Fatal error:  Uncaught Error: Call to undefined method MyClass::__set_state() in C:\test.php(15) : eval()'d code:1
Stack trace:
#0 C:\test.php(15): eval()
#1 {main}
  thrown in C:\test.php(15) : eval()'d code on line 1

设置 __set_state 魔术方法的逻辑以复原对象

__set_state() 魔术方法通过 var_export() 提供的 原始对象的属性信息 将能够对原始对象进行还原。对此,请参考如下示例:

<?php


class MyClass
{
    static function __set_state($obj_details) {
        # 将自生实例化为一个对象
        $obj = new self();
        # 循环遍历由原始对象的属性信息组成的数组
        foreach($obj_details as $key => $value) {
            # 将关联数组中的键作为对象的属性,
            # 值作为相应属性的属性值。
            $obj -> $key = $value;
        }
        # 将复原对象作为返回值进行返回
        return $obj;
    }
}

$myClass = new MyClass();

$myClass -> name = "RedHeart";
$myClass -> age = 19;
$myClass -> nation = "China";

# 通过 var_export(?, true) 获取对象的可解析字符串并将其输出至终端
$indicate_text = var_export($myClass, true);
print($indicate_text . "\n");

# 复原原始对象并将对象的结构输出至终端
$result = eval('return ' . $indicate_text . ";");
var_dump($result);

执行效果

MyClass::__set_state(array(
   'name' => 'RedHeart',
   'age' => 19,
   'nation' => 'China',
))
object(MyClass)#2 (3) {
  ["name"]=>
  string(8) "RedHeart"
  ["age"]=>
  int(19)
  ["nation"]=>
  string(5) "China"
}

注意事项

var_export()eval() 两者的配合进行对象的数据持久化与复原的过程中,var_export() 函数并不是必须存在的,若对 var_export 函数的输出信息较为了解,则 可以自行构造所需的字符串以实现对象的数据持久化
而在 eval() 函数使用原始对象的属性信息复原对象时,需要调用所属类的 __set_state() 方法,这就意味着被复原对象的所属类必须在尝试复原对象前进行定义。
调用 __set_state() 方法复原对象与类的实例对象无关(可以在类不被实例化任何对象时进行),故需要将 __set_state() 方法设置为静态方法。否则,PHP 将抛出 Fatal Error 异常并立即停止运行。

对于 var_export() 与 eval() 两者的配合进行对象的数据持久化与复原的过程中 需要注意的事项整理如下:

  1. var_export() 函数并不是获取对象可解析字符串的 唯一方式
  2. 被复原对象的所属类必须 在尝试复原对象前进行定义
  3. __set_state() 魔术方法必须被定义为 静态方法

举个栗子

<?php


class MyClass
{
    static function __set_state($obj_details) {
        $obj = new self();
        foreach($obj_details as $key => $value) {
            $obj -> $key = $value;
        }
        return $obj;
    }
}

# 自定义对象的可解析字符串
$indicate_text = "MyClass::__set_state(array(
                    'name' => 'RedHeart',
                    'age' => 19,
                    'nation' => 'China',
                   ))";

$result = eval('return ' . $indicate_text . ";");
var_dump($result);

执行效果

object(MyClass)#1 (3) {
  ["name"]=>
  string(8) "RedHeart"
  ["age"]=>
  int(19)
  ["nation"]=>
  string(5) "China"
}

通用内置空类 stdClass

stdClass

stdClass 是 PHP 提供的一个 基础类,用于创建一个 没有预定义结构的空对象(stdClass 中没有定义任何成员)stdClass 的结构大致如此:

class stdClass {}

stdClass 提供了一种方式,允许开发者 在运行时动态地创建和管理对象属性,而不必预先定义一个完整的类。对此,请参考如下示例:

<?php


// stdClass 属于 PHP 的基础类,
// 是 PHP 的一部分,可以直接进行使用。
$myClass = new stdClass();

// 在 PHP 运行过程中动态的对属性进行创建与管理
$myClass -> name = "RedHeart";
$myClass -> nation = "BinaryMoon";
$myClass -> nation = "China";

print_r($myClass);

执行效果

stdClass Object
(
    [name] => RedHeart
    [nation] => China
)

对 __set_state() 的天然支持

PHP 的内置类 stdClass 尽管是一个空类但却对 __set_state() 魔术方法存在 天然的支持(PHP 内部已为 stdClass 实例对象提供了 __set_state 实现)。对此,请参考如下示例:

<?php


$myClass = new stdClass();

# 获取 stdClass 实例对像的方法列表并将其输出
print_r(get_class_methods($myClass));

# 定义 stdClass 实例对象的可解析字符串
$indicate_text = "(object)array(
                    'name' => 'RedHeart',
                    'age' => 19,
                    'nation' => 'China',
                   )";

# 尝试通过 eval() 函数还原 stdClass 对象
$result = eval('return ' . $indicate_text . ';');
print_r($result);

执行效果

由上述示例代码的执行结果可知,即使 stdClass 未定义 __set_state 方法,该方法也能被成功被调用并执行还原对象的功能

Array
(
)
stdClass Object
(
    [name] => RedHeart
    [age] => 19
    [nation] => China
)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1093137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UI自动化测试 —— Jenkins配置

前一段时间帮助团队搭建了UI自动化环境&#xff0c;这里将Jenkins环境的一些配置分享给大家。 背景&#xff1a; 团队下半年的目标之一是实现自动化测试&#xff0c;这里要吐槽一下&#xff0c;之前开发的测试平台了&#xff0c;最初的目的是用来做接口自动化测试和性能测试&…

数睿通2.0:高效的数据处理,主数据与数据表功能全面升级

引言 八天很短&#xff0c;七天很长&#xff0c;数睿通 2.0 数据中台也随之迎来了新一轮的版本迭代&#xff0c;本次更新主要包括&#xff1a; 主数据模型&#xff08;可视化建模&#xff09;主数据派发&#xff08;支持派发主数据到下游数据表&#xff0c;rabbitMq&#xff…

字节码学习之常见java语句的底层原理

文章目录 前言1. if语句字节码的解析 2. for循环字节码的解析 3. while循环4. switch语句5. try-catch语句6. i 和i的字节码7. try-catch-finally8. 参考文档 前言 上一章我们聊了《JVM字节码指令详解》 。本章我们学以致用&#xff0c;聊一下我们常见的一些java语句的特性底层…

苍穹外卖(四) AOP切面公共字段自动填充及文件上传

一.AOP切面公共字段填充 问题分析 如果都按照上述的操作方式来处理这些公共字段, 需要在每一个业务方法中进行操作, 编码相对冗余、繁琐&#xff0c;那能不能对于这些公共字段在某个地方统一处理&#xff0c;来简化开发呢&#xff1f; 答案是可以的&#xff0c;我们使用AOP切…

Redis订阅和发布

Redis订阅和发布 一、订阅者和发布者二、使用示例三、常用命令 一、订阅者和发布者 发布者&#xff1a;publish&#xff0c;发送消息订阅者&#xff1a;subscribe&#xff0c;接收消息 如下图所示&#xff0c;可以有多个订阅者订阅同一个频道&#xff0c;如果该频道发送消息&…

【RocketMQ系列一】初识RocketMQ

您好&#xff0c;我是码农飞哥&#xff08;wei158556&#xff09;&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精…

thinkphp6入门(9)-- 获取url路径中的应用名、控制器名、操作名

如果使用了多应用模式&#xff0c;可以通过下面的方法来获取当前应用 app(http)->getName(); 获取当前控制器 Request::controller(); 获取当前操作 Request::action(); 在中间件middleware中是无法获取控制器和操作的 需要将middleware的引入修改为 config 目录下的 ro…

计算机网络 实验六 Wireshark 抓包实验

实验目的&#xff1a; 通过实验掌握下列知识&#xff1a; 1. 掌握Wireshark抓包工具的使用。 2. 掌握建立telnet用户密码登录方式&#xff0c;并通过wireshark抓取相关信息。 3. 理解TCP的包结构&#xff0c;并掌握TCP建立连接的过程。 4. 掌握使用tftp工具&#xff0c;上…

一文带你了解以色列的当红38家网络安全公司

2014年&#xff0c;以色列出口的网络安全产品总值达60亿美金&#xff0c;占领了全球10%的网络安全市场。2014-2016年&#xff0c;微软用3.2亿美元买下数据隐私公司Adallom&#xff1b;Facebook花了1.5亿美元收购移动端数据分析公司Onavo&#xff1b;PayPal以6千万美元收下CyAct…

2023面试知识点二

1、vue双向绑定是如何实现的 原理主要通过数据劫持和发布订阅模式实现的通过Object.defineProperty()来劫持各个属性的setter&#xff0c;getter&#xff0c;监听数据的变化在数据变动时发布消息给订阅者(watcher)&#xff0c;订阅者触发响应的回调(update)更新视图。 2、ing…

非一线工程管理者的一对一沟通

一线工程管理者主要管理/领导工程师完成实际的工程任务&#xff0c;而非一线的工程管理者需要领导一线管理者&#xff0c;更多的关注团队本身&#xff0c;因此两者在做一对一沟通的时候需要有不同的关注点。原文: One-on-Ones for (Engineering) Manager of Managers 如果没有耐…

Linux该如何学习,给你支招

如果你已经确定对 Linux 产生了兴趣&#xff0c;那么接下来我们介绍一下学习 Linux 的方法。这只是自己关于学习Linux的建议。 一、如何去学习 学习大多类似庖丁解牛&#xff0c;对事物的认识一般都是由浅入深、由表及里的过程&#xff0c;循序才能渐进。学习 Linux 同样要有一…

复旦MBA魏文童:构建完备管理知识体系,助力企业数字化发展

日月光华&#xff0c;旦复旦兮&#xff01;复旦MBA如同一个巨大的磁场&#xff0c;吸引了诸多来自五湖四海、各行各业的职场精英。从初入职场的青涩懵懂到如今的独当一面专业干练&#xff0c;他们逐渐成长为职场的中坚力量&#xff0c;在各自领域内发光发热。作为新时代的青年&…

怒刷LeetCode的第27天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;位运算 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;贪心算法 第三题 题目来源 题目内容 解决方法 方法一&#xff1a;二分查找 方法二&#xff1a;牛顿迭代法 方法三&#xff1a;位操作…

基于Pytest接口自动化的requests模块项目实战以及接口关联方法详解

1、基于pytest单元测试框架的规则 1.1 模块名&#xff08;即文件名&#xff09;必须以test_开头或者_test结尾 1.2 类名必须以Test开头且不能有init方法 1.3 用例名&#xff08;测试方法&#xff09;必须以test开头 同时&#xff0c;我也为大家准备了一份软件测试视频教程&…

【算法-动态规划】零钱兑换 II-力扣 518

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kuan 的首页,持续学…

Smartforms 打印出现的问题

上半年ECC做了升级 程序代码从ECC迁移到S4 有用户反馈 打印不能用了 经过调试发现在打印程序中 竟然返回2&#xff0c;但是 smartforms ZRPT_CO_YFLL_DY又是存在的 。 然后去激活 并与 ECC对比发现问题 S4的页大小竟然这么小 找到对应的页格式 对比ECC和S4 果然是这个…

2023年中国商用服务机器人行业发展概况分析:国产机器人厂商向海外进军[图]

商用服务机器人指在非制造业的商用服务场景中&#xff0c;用来替代或辅助人类进行服务性质工作的机器人&#xff1b;常见的商用场景中&#xff0c;商用服务机器人主要分为终端配送类机器人&#xff0c;商用清洁类机器人&#xff0c;引导讲解类机器人等&#xff0c;被广泛应用在…

7+线粒体相关基因预后模型+肿瘤微环境+免疫细胞浸润+实验验证

今天给同学们分享一篇线粒体预后模型实验的生信文章“Constructing a novel mitochondrial-related gene signature for evaluating the tumor immune microenvironment and predicting survival in stomach adenocarcinoma”&#xff0c;这篇文章于2023年3月13日发表在J Trans…

Spring Boot 生成二维码

效果图 1.maven依赖 <dependency> <groupId>com.google.zxing</groupId> <artifactId>javase</artifactId>