【PHP小课堂】一起学习PHP中的反射(一)

一起学习PHP中的反射(一)

反射这个名词相信大家不会陌生,但反过来说,这个反射到底是一个什么概念呢?其实反射,就是通过一些方法函数,来获得一个类或者一个实例化对象中的一些信息。当然,更重要的是,它可以是在运行时来动态获取这些信息的。这样的话,有很多功能就可以通过反射来实现了。比如说 Java 中的注解,在一些 PHP 的框架中,要实现类似的注解功能,就是通过反射来获得注释中的信息来实现的。大家可以参考 Hyperf 框架中的注解功能。

在学习的过程中,我们还是一步一步的来看看这些反射相关的类及方法是如何使用的。反射也是进阶高级程序员所必备的能力,同时,这个能力也是大部分语言都支持的,不仅限于 PHP ,在 Java 中,反射也是非常常用的特性之一。

获得一个反射类的全部信息

首先,我们来学习的是反射一个类中的信息。注意,类指的是模板,不是一个实例化的对象。所以我们反射出来的内容都是固定写死在类中的,这个我们后面还会讲到,反射类和反射对象是有不同的。

class A{/*** This is ONE DOC.*/const ONE = 'number 1';// This is TWO DOC.private const TWO = 'number 2';/*** This is a DOC.*/private $a = '1';// This is b DOC.protected $b = '2';/* This is c DOC. */public $c = '3';public $d;static $e = '5';static $f;private function testA(){echo 'This is class A, function testA', PHP_EOL;}protected function testB(){echo 'This is class A, function testB', PHP_EOL;}public function testC(){echo 'This is class A, function testC', PHP_EOL;}
}

首先,我们要定义一个用于测试的类。当然,反射相关的操作是可以对系统环境中的全部类和对象都起作用的。不过为了便于测试,我们还是通过一个自定义的类来进行演示。在这个类中,我们有一些属性和方法,有不同的访问修饰符,也有一些不同的注释。今天我们主要研究的是属性方面的操作,所以方法这块就是简单地定义了三个不同访问修饰符的方法。等到后面的文章需要深入地学习方法相关的反射操作时,再增加这个类中关于方法及其它方面的内容。

然后我们先看一下一次性地反射整个类中的信息的方法。

ReflectionClass::export(new ReflectionClass('A'));
// Class [ <internal:Reflection> class ReflectionClass implements Reflector ] {//     - Constants [3] {
//       Constant [ public int IS_IMPLICIT_ABSTRACT ] { 16 }
//       Constant [ public int IS_EXPLICIT_ABSTRACT ] { 32 }
//       Constant [ public int IS_FINAL ] { 4 }
//     }//     - Static properties [0] {
//     }//     - Static methods [1] {
//       Method [ <internal:Reflection, prototype Reflector> static public method export ] {//         - Parameters [2] {
//           Parameter #0 [ <required> $argument ]
//           Parameter #1 [ <optional> $return ]
//         }
//       }
//     }//     - Properties [1] {
//       Property [ <default> public $name ]
//     }//  ……………………………………
//  ……………………………………
//  ……………………………………
//  ……………………………………//       Method [ <internal:Reflection> public method getExtension ] {//         - Parameters [0] {
//         }
//       }//       Method [ <internal:Reflection> public method getExtensionName ] {//         - Parameters [0] {
//         }
//       }//       Method [ <internal:Reflection> public method inNamespace ] {//         - Parameters [0] {
//         }
//       }//       Method [ <internal:Reflection> public method getNamespaceName ] {//         - Parameters [0] {
//         }
//       }//       Method [ <internal:Reflection> public method getShortName ] {//         - Parameters [0] {
//         }
//       }
//     }
//   }

ReflectionClass 类就是用于反射一个类的相关信息的类模板,它的这个静态的 export() 方法就是用于报告这个类的全部信息。不过这个方法已经在 PHP7.4 中被标记为过时的,并且在 PHP8 中被移除了。其实对于所有反射相关的类来说,包括我们下面要学习的 ReflectionClassConstant 和 ReflectionProperty 对象,在之前都会有这个 export() 方法,但是现在它们都实现了 __toString() 方法,也就是说,直接打印它们就可以代替原来的 export() 方法了。

$obj = new ReflectionClass('A');
echo $obj;
// Class [ <user> class A ] {
//     @@ /Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/05/source/1.一起学习PHP中的反射(一).php 3-41//     - Constants [2] {
//       Constant [ public string ONE ] { number 1 }
//       Constant [ private string TWO ] { number 2 }
//     }//     - Static properties [2] {
//       Property [ public static $e ]
//       Property [ public static $f ]
//     }//     - Static methods [0] {
//     }//     - Properties [4] {
//       Property [ <default> private $a ]
//       Property [ <default> protected $b ]
//       Property [ <default> public $c ]
//       Property [ <default> public $d ]
//     }//     - Methods [3] {
//       Method [ <user> private method testA ] {
//         @@ /Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/05/source/1.一起学习PHP中的反射(一).php 30 - 32
//       }//       Method [ <user> protected method testB ] {
//         @@ /Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/05/source/1.一起学习PHP中的反射(一).php 34 - 36
//       }//       Method [ <user> public method testC ] {
//         @@ /Users/zhangyue/MyDoc/博客文章/dev-blog/php/2021/05/source/1.一起学习PHP中的反射(一).php 38 - 40
//       }
//     }
//   }

直接打印出来的内容是不是更清晰明了。我们可以看到在类中定义的常量、属性、方法,但是需要注意的是,静态属性在这里是不会打印出来的哦。ReflectionClass 类的构造函数需要传递一个类的名称过来,这样它就可以返回一个针对指定的这个类的反射类对象。注意,现在我们获得的这个 obj 对象就是针对 A 类的一个反射类了。后面学习的操作都是通过这个 obj 对象来实现的。

反射类中的常量信息

既然有了全局的输出,那么我们再来看看单独的一些操作。首先就是看一下获取常量相关信息的操作。

print_r($obj->getConstants());
// Array
// (
//     [ONE] => number 1
//     [TWO] => number 2
// )echo $obj->getConstant('ONE'), PHP_EOL;// number 1var_dump($obj->hasConstant('TWO')); // bool(true)
var_dump($obj->hasConstant('THREE')); // bool(false)

可以通过 getConstants() 方法获得全部的常量信息数据,也可以通过 getConstant() 方法获得指定的常量值,也可以通过 hasConstant() 方法判断指定的某个常量是否存在。另外,也可以获得常量对象信息,也就是我们下面要讲的 ReflectionClassConstant 对象。

ReflectionClassConstant

var_dump($obj->getReflectionConstants());
// array(2) {
//     [0]=>
//     object(ReflectionClassConstant)#2 (2) {
//       ["name"]=>
//       string(3) "ONE"
//       ["class"]=>
//       string(1) "A"
//     }
//     [1]=>
//     object(ReflectionClassConstant)#3 (2) {
//       ["name"]=>
//       string(3) "TWO"
//       ["class"]=>
//       string(1) "A"
//     }
//   }var_dump($obj->getReflectionConstant('ONE'));
// object(ReflectionClassConstant)#3 (2) {
//     ["name"]=>
//     string(3) "ONE"
//     ["class"]=>
//     string(1) "A"
//   }

getReflectionConstants() 用于获得常量反射对象数组,也就是我们的反射对象中全部的常量信息。getReflectionConstant() 获得指定的单个常量反射对象。接下来我们就看看这个 getReflectionConstants 对象中都有什么操作。

$objContant1 = $obj->getReflectionConstant('ONE');
$objContant2 = $obj->getReflectionConstant('TWO');var_dump($objContant1->getName()); // string(3) "ONE"
var_dump($objContant2->getName()); // string(3) "TWO"var_dump($objContant1->getValue()); // string(8) "number 1"
var_dump($objContant2->getValue()); // string(8) "number 2"var_dump($objContant1->getDocComment());
// string(35) "/**
// * This is ONE DOC.
// */"var_dump($objContant2->getDocComment()); // bool(false)var_dump($objContant1->getDeclaringClass());
// object(ReflectionClass)#4 (1) {
//     ["name"]=>
//     string(1) "A"
//   }

我们可以通过 getName() 获得这个常量反射对象对应的常量键名,也可以通过 getValue() 获得它的值。

当然,这里更重要的一点是通过 getDocComment() 获得这个常量反射对象的注释信息。从测试代码中可以看出,我们能获取到的是标准的 DOC 格式的注释内容,普通的 // 以及 /* */ 这样的注释内容是无法获取到的。这一点在最前面关于反射的说明中也说过,注解功能正是通过反射这些注释中的内容实现的。DOC 格式的注释中是可以有 @ 修饰符号的,很多内容就可以通过这个 @ 修饰符号来进行,这个我们后面再说。现在的这个方法只是获取到注释里面的文字内容。

接下来就是一个 getDeclaringClass() 方法,返回的就是这个常量反射对象所对应的类模板是哪个,在这里我们可以看到输出的结果是对应的反射类 A 。注意,它返回的不是那个真实的 A 类,而是我们 obj 对应的那个 A 类的反射对象。

var_dump($objContant1->getModifiers()); // int(256)
var_dump($objContant2->getModifiers()); // int(1024)var_dump($objContant1->isPrivate()); // bool(false)
var_dump($objContant1->isProtected()); // bool(false)
var_dump($objContant1->isPublic()); // bool(true)

最后,我们看到的是关于这个常量反射对象对应的常量的访问修饰符的信息获取操作,通过 getModifiers() 方法,可以获得这个常量对应的访问修饰符,它返回的是一个数字类型,实际上对应的是几个常量,256 对应的是 IS_PUBLIC, 1024 对应的是 IS_PRIVATE ,另外还有一个 512 对应的是 IS_PROTECTED 。当然,我们还有更简单的方法,就是通过下面的 isPrivate() 、isProtectd() 和 isPublic() 方法来直接获得判断结果。

反射类中的属性信息

类中的属性信息其实和常量信息的内容是差不多的,只是它多了针对静态属性相关的操作而已。

var_dump($obj->getDefaultProperties());
// array(6) {
//     ["e"]=>
//     string(1) "5"
//     ["f"]=>
//     NULL
//     ["a"]=>
//     string(1) "1"
//     ["b"]=>
//     string(1) "2"
//     ["c"]=>
//     string(1) "3"
//     ["d"]=>
//     NULL
//   }

getDefaultProperties() 方法用于获取反射类对象中的所有默认属性,其实就是我们定义在类中的属性,它只是通过键值的形式返回属性信息,没有别的内容。真正对应属性的操作,还是集中于属性相关的属性反射对象,也就是 ReflectionProperty 这个对象。

ReflectionProperty

var_dump($obj->getProperties());
// array(6) {
//     [0]=>
//     object(ReflectionProperty)#2 (2) {
//       ["name"]=>
//       string(1) "a"
//       ["class"]=>
//       string(1) "A"
//     }
//     [1]=>
//     object(ReflectionProperty)#3 (2) {
//       ["name"]=>
//       string(1) "b"
//       ["class"]=>
//       string(1) "A"
//     }
//     [2]=>
//     object(ReflectionProperty)#4 (2) {
//       ["name"]=>
//       string(1) "c"
//       ["class"]=>
//       string(1) "A"
//     }
//     [3]=>
//     object(ReflectionProperty)#5 (2) {
//       ["name"]=>
//       string(1) "d"
//       ["class"]=>
//       string(1) "A"
//     }
//     [4]=>
//     object(ReflectionProperty)#6 (2) {
//       ["name"]=>
//       string(1) "e"
//       ["class"]=>
//       string(1) "A"
//     }
//     [5]=>
//     object(ReflectionProperty)#7 (2) {
//       ["name"]=>
//       string(1) "f"
//       ["class"]=>
//       string(1) "A"
//     }
//   }var_dump($obj->getProperty('a'));
// object(ReflectionProperty)#7 (2) {
//     ["name"]=>
//     string(1) "a"
//     ["class"]=>
//     string(1) "A"
//   }

getProperties() 用于获取反射属性对象列表,getProperty() 用于获取指定的反射属性对象。

$objPro1 = $obj->getProperty('a');
$objPro2 = $obj->getProperty('b');
$objPro3 = new ReflectionProperty('A', 'c');
$objPro4 = $obj->getProperty('d');
$objPro5 = $obj->getProperty('e');// $objPro111 = $obj->getProperty('aaa');  // PHP Fatal error:  Uncaught ReflectionException: Property aaa does not exist

我们获取类中全部需要测试的属性,在这里,我们使用了另一种通过实例化 ReflectionProperty 类来获取指定类中的反射属性的方式来获得这个对象。这种形式其实上面的 ReflectionClassConstant 也是支持的。另外,如果指定的属性不存在的话,会报直接中断脚本运行的错误信息。

var_dump($objPro1->getName()); // string(1) "a"
// var_dump($objPro1->getValue(new A)); // PHP Fatal error:  Uncaught ReflectionException: Cannot access non-public member A::$a var_dump($objPro3->getValue(new A)); // string(1) "3"var_dump($objPro1->getDocComment());
// string(33) "/**
//      * This is a DOC.
//      */"
var_dump($objPro2->getDocComment()); // bool(false)
var_dump($objPro3->getDocComment()); // bool(false)var_dump($objPro1->getDeclaringClass());
// object(ReflectionClass)#4 (1) {
//     ["name"]=>
//     string(1) "A"
//   }var_dump($obj->hasProperty('a')); // bool(true)
var_dump($obj->hasProperty('aa')); // bool(false)

这几个方法,getName()、getValue()、getDocComment()、getDeclaringClass() 和上面学习过的常量当中的方法是没有什么区别的。不过要注意的是,我们反射出来的内容,只能是 Public 的哦,如果反射能够直接反射获得私有和受保护的属性值的话,那么封装的意义就不存在了,不过我们也可以通过另外一个方法来获得这些属性的值。

$objPro1->setAccessible(true);
var_dump($objPro1->getValue(new A)); // string(1) "1"

嗯,说好封装还是被我们给破坏了,说实话,在使用反射的时候对于封装的保护是一个重要的议题,这也是我们在业务开发中需要重点关注的内容。

还有就是 getValue() 需要传入一个实例化对象,这又是为什么呢?常量那边不需要是因为常量是固定的,不可改变的,而普通属性是可以改变的,也就是说,即使给了默认值,在运行时这个属性的值也是不一定的,不能直接将类模板中的属性值反射回来,而必须要根据具体的实例化对象来确定这个属性的值。

既然属性的值有这样的问题,那么我们能不能通过反射来修改属性的值呢?当然可以啦,在属性这边是有一个对应的 setValue() 方法的。

$classA = new A;
$objPro4->setValue($classA, 'This is d value.');
var_dump($classA->d); // string(16) "This is d value."

关于访问修饰符的内容,属性和常量的方法也是完全一样的,这里就只展示出来不做过多的解释了。

var_dump($objPro1->getModifiers()); // int(1024)
var_dump($objPro2->getModifiers()); // int(512)
var_dump($objPro3->getModifiers()); // int(256)var_dump($objPro1->isPrivate()); // bool(true)
var_dump($objPro1->isProtected()); // bool(false)
var_dump($objPro1->isPublic()); // bool(false)var_dump($objPro1->isDefault()); // bool(true)var_dump($objPro1->isStatic()); // bool(false)
var_dump($objPro5->isStatic()); // bool(true)

在这里,我们还多了两个方法,一个是 isDefault() 用于判断这个属性是否是默认属性,也就是是否是定义在这个类模板中的。而另一个 isStatic() 方法,则用于判断这个属性反射对象是否是静态属性。

另外,还有一些方法是在 PHP7.4 以后才提供的,我这里是 PHP7.3 ,没有进行过测试,只是列出来供大家参考。

// PHP8
// var_dump($objPro1->getDefaultValue());
// var_dump($objPro1->hasDefaultValue());
// PHP7.4
// var_dump($objPro3->isInitialized());
// var_dump($objPro3->getType());
// var_dump($objPro3->hasType());

静态属性列表

最后,对应静态属性来说,还有两个特殊的方法是专门用于静态属性的列表及单个信息获取的。

var_dump($obj->getStaticProperties());
// array(2) {
//     ["e"]=>
//     string(1) "5"
//     ["f"]=>
//     NULL
//   }var_dump($obj->getStaticPropertyValue('e')); // string(1) "5"

总结

今天一开篇的内容就不少吧,毕竟反射是一个非常大的功能集,也是我们向更高层次迈进的一个重要的知识点。所以后面我们的学习也会更加的艰苦,大家做好心理准备了吗?

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/05/source/1.%E4%B8%80%E8%B5%B7%E5%AD%A6%E4%B9%A0PHP%E4%B8%AD%E7%9A%84%E5%8F%8D%E5%B0%84%EF%BC%88%E4%B8%80%EF%BC%89.php

参考文档:

https://www.php.net/manual/zh/book.reflection.php

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RocketMQ快速开始

前置推荐阅读&#xff1a;RocketMQ简介-CSDN博客 本地部署 RocketMQ 这一节介绍如何快速部署一个单节点单副本 RocketMQ 服务&#xff0c;并完成简单的消息收发。 系统要求 64位操作系统&#xff0c;推荐 Linux/Unix/macOS64位 JDK 1.8 1.下载安装Apache RocketMQ​ RocketMQ…

aws 把vpc残留删除干净

最近忘了把vpc 删干净导致又被收了冤大头钱 在删除vpc 的收发现又eni在使用&#xff0c;但是忘了是哪个资源在占用 先用命令行把占用的资源找出来停掉 使用 AWS 命令行界面&#xff08;CLI&#xff09;来查看 VPC 的使用情况 列出子网&#xff1a; aws ec2 describe-subnets …

抖音列表页采集-前言

准备工作&#xff1a; 1.关于selenium介绍&#xff1a; python自动化入门的话&#xff0c;selenium绝对是最方便的选择&#xff0c;基本逻辑即为&#xff1a;程序模拟人的行为操作浏览器&#xff0c;这样的操作需要借用浏览器驱动&#xff0c;我选用的是chrome浏览器&#xff…

浮动练习(3)

##每台电脑分辨率不同&#xff0c;数值高度宽度需要自己调&#xff0c;仅供参考 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title></title> <style> div{ …

港大和字节提出长视频生成模型Loong,可生成具有一致外观、大运动动态和自然场景过渡的分钟级长视频。

HKU, ByteDance&#xff5c;⭐️ 港大和字节联合提出长视频生成模型Loong&#xff0c;该模型可以生成外观一致、运动动态大、场景过渡自然的分钟级长视频。选择以统一的顺序对文本标记和视频标记进行建模&#xff0c;并使用渐进式短到长训练方案和损失重新加权来克服长视频训练…

MATLAB(Octave)混电动力能耗评估

&#x1f3af;要点 处理电动和混动汽车能耗的后向和前向算法模型(simulink)&#xff0c;以及图形函数、后处理函数等实现。构建储能元数据信息&#xff1a;电池标称特性、电池标识符等以及静止、恒定电流和恒定电压等特征阶段。使用电流脉冲或要识别的等效电路模型类型配置阻抗…

多功能纤维上线,大脑肠道 “无线畅聊” 不是梦

大家好&#xff01;今天来了解一篇多功能微电子纤维研究——《Multifunctional microelectronic fibers enable wireless modulation of gut and brain neural circuits》发表于《Nature Biotechnology》。我们都知道大脑和内脏器官的沟通对生存至关重要&#xff0c;可一直以来…

为您的 WordPress 网站打造完美广告布局 A5广告单元格插件

一个为 WordPress 网站量身定制的强大工具,它将彻底改变您展示广告的方式 灵活多变的布局设计 A5 广告单元格插件的核心优势在于其无与伦比的灵活性。无论您是想要创建整齐的网格布局,还是希望打造独特的不规则设计,这款插件都能满足您的需求。 自定义网格数量&#xff1a;从 2…

生命科学的前沿挑战与未来机遇

生命科学的前沿挑战与未来机遇 一、引言 21世纪被誉为生命科学的世纪&#xff0c;生命科学的迅猛发展为人类的健康、环境和社会经济带来了巨大的变革。从基因编辑技术的突破&#xff0c;到合成生物学的兴起&#xff0c;再到生物医药的快速进步&#xff0c;生命科学的前沿挑战…

如何使用 Browserless 抓取动态网站?

什么是动态网页&#xff1f; 动态网页是指其内容并非完全直接嵌入在静态HTML中&#xff0c;而是通过服务器端或客户端渲染生成的网页。 它可以根据用户的操作实时显示数据&#xff0c;例如在用户点击按钮或向下滚动页面时加载更多内容&#xff08;如无限滚动&#xff09;。这…

DolphinDB 2024 年度峰会回顾之分论坛:权益类数字基建与技术创新

在这个数字化时代&#xff0c;金融科技正以前所未有的速度发展&#xff0c;而权益类数字基建作为这一进程的核心支撑&#xff0c;正不断推动着金融领域的创新与变革。 DolphinDB 2024 年度峰会的分论坛 A 聚焦《权益类数字基建与技术创新》这一核心议题&#xff0c;邀请到了业…

携手并进,智驭教育!和鲸科技与智谱 AI 签署“101 数智领航计划”战略合作协议

近日&#xff0c;上海和今信息科技有限公司&#xff08;以下简称“和鲸科技”&#xff09;与北京智谱华章科技有限公司&#xff08;以下简称“智谱 AI”&#xff09;签署“101 数智领航计划”战略合作协议。双方将携手营造智能化学科教育与科研环境&#xff0c;提供多种大模型工…

HTTP协议讲解

前瞻&#xff1a; 认识URL 1.ipport 2.平时上网&#xff0c;就是进程间通信 3.上网行为&#xff0c;1.获取资源 2.上传数据 相当于I/O 4.http协议采用tcp协议 网页 图片 音乐其实都是资源 Http请求 http request Method&#xff1a;Get/Post资源/路径&#xff1a…

GitLab 老旧版本如何升级?

极狐GitLab 正式对外推出 GitLab 专业升级服务 https://dl.gitlab.cn/cm33bsfv&#xff01; 专业的技术人员为您的 GitLab 老旧版本实例进行专业升级&#xff01;服务详情可以在官网查看详细解读&#xff01; 那些因为老旧版本而被攻击的例子 话不多说&#xff0c;直接上图&a…

通用大模型应用研究七:RAGOS和AgentOS

RAG&#xff0c;即检索增强生成&#xff08;Retrieval-Augmented Generation&#xff09;&#xff0c;是一种结合了信息检索和大型语言模型&#xff08;LLM&#xff09;提示的技术。它通过从数据源检索相关信息&#xff0c;并将检索到的信息与问题一起注入到LLM提示中&#xff…

一起赚美元第九期及相关推荐

一、核心内容 &#xff08;一&#xff09;一起赚美元第九期文章导读 作者复盘了在 10 天内通过知识付费赚到 220750 美元的故事。运营数据&#xff1a;24 号课程做完&#xff0c;28 号课程开卖&#xff0c;10 天后 262 人付款&#xff0c;均价 800 美元&#xff0c;总金额 22…

【Android】事件分发机制

Android 的事件分发机制主要包括以下几个步骤&#xff1a; 事件生成&#xff1a;用户在设备上进行触摸、滑动等操作时&#xff0c;系统会生成相应的事件&#xff0c;如触摸事件&#xff08;MotionEvent&#xff09;。 事件发送&#xff1a;生成的事件会被发送到当前活动&#…

【linux】线程 (三)

13. 常见锁概念 &#xff08;一&#xff09;了解死锁 死锁是指在一组进程中的各个进程均占有不会释放的资源&#xff0c;但因互相申请被其他进程占有的&#xff0c;且不释放的资源&#xff0c;而处于的一种永久等待状态 &#xff08;二&#xff09;死锁四个必要条件 互斥条件…

uniapp项目结构基本了解

基本结构的解释 App.vue&#xff1a;应用的根组件&#xff0c;定义全局布局和逻辑。pages/&#xff1a;存放各个页面的 .vue 文件&#xff0c;定义应用的具体页面和功能模块。main.js&#xff1a;应用入口文件&#xff0c;初始化应用&#xff0c;挂载 App.vue。manifest.json&…

【C++】— 一篇文章让你认识STL

文章目录 &#x1f335;1.什么是STL&#xff1f;&#x1f335;2.STL的版本&#x1f335;3.STL的六大组件&#x1f335;4.STL的重要性&#x1f335;5. 如何学习STL&#x1f335;6. 学习STL的三种境界 &#x1f335;1.什么是STL&#xff1f; STL是Standard Template Library的简称…