PHP面向对象深入理解之五(内省函数与反射类)

素颜马尾好姑娘i 2022-06-10 09:27 214阅读 0赞

#

1. 内省(Introspection)函数

Introspection(内省)程序在运行时检查对象的类型或属性的能力,他允许对象类由程序员操纵。
你将会发现introspection 相当有用当你不知道哪一个类后或者方法在设计时需要被执行.

Introspection 在 PHP 提供非常有用的能力去检查类(classes), 接口(interfaces), 属性(properties),
和方法(methods). PHP 提供了大量的函数你能用他来完成这些检查任务.
为了帮助你理解introspection, 我将简要概述一些 PHP的 类(classes),方法(methods), 和函数(functions)
他们被使用的时候,代码会高亮显示.

通过这篇文章, 你将会看到一组例子如何去使用一些非常有用的 PHP的 introspection 函数
以及专门针对API提供类似于introspection功能的部分, 反射(Reflection) API.

第一个例子, 我会展示一些 PHP的 introspection functions. 你能使用这些功能functions
去检查基础的信息包括关于类(classes)像他们的名字(name), 父类的名字等等.

  1. <?php
  2. class_exists() # 检查一个类是否被定义
  3. get_class() # 返回对象的类名
  4. get_parent_class() # 返回对象的类的父类名
  5. is_subclass_of() # 检查一个对象是否是给定父类的 子类
  6. ?>

下面是一个例子 PHP 包含定义Introspection 和子类以及输出输出通过上述功能提取的信息:

  1. <?php
  2. class Introspection
  3. {
  4. public function description() {
  5. echo "I am a super class for the Child class.n";
  6. }
  7. }
  8. class Child extends Introspection
  9. {
  10. public function description() {
  11. echo "I'm " . get_class($this) , " class.n";
  12. echo "I'm " . get_parent_class($this) , "'s child.n";
  13. }
  14. }
  15. if (class_exists("Introspection")) {
  16. $introspection = new Introspection();
  17. echo "The class name is: " . get_class($introspection) . "n";
  18. $introspection->description();
  19. }
  20. if (class_exists("Child")) {
  21. $child = new Child();
  22. $child->description();
  23. if (is_subclass_of($child, "Introspection")) {
  24. echo "Yes, " . get_class($child) . " is a subclass of Introspection.n";
  25. }
  26. else {
  27. echo "No, " . get_class($child) . " is not a subclass of Introspection.n";
  28. }
  29. }
  30. ?>

输出如下:

The class name is: Introspection
I am a super class for the Child class.
I’m Child class.
I’m Introspection’s child.
Yes, Child is a subclass of Introspection.

这是第二个例子,其中包含ICurrencyConverter接口和GBPCurrencyConverter类的定义,
并输出上面列出的函数提取的信息。 与第一个例子一样,我将首先列出这些函数,然后显示一些代码。

  1. <?php
  2. get_declared_classes() # 返回一系列已经定义的类
  3. get_class_methods() # 返回给定【类|对象】的所有方法 private 和 protected 方法会被跳过
  4. get_class_vars() # 返回当前【类名】的默认属性 private 和 protected 属性会被跳过
  5. interface_exists() # 检查某个【接口名】是否 被定义
  6. method_exists() # 检查一个类/对象是否定义某个方法
  7. ?>

我们看个栗子:

  1. <?php
  2. interface ICurrencyConverter
  3. {
  4. public function convert($currency, $amount);
  5. }
  6. class GBPCurrencyConverter implements ICurrencyConverter
  7. {
  8. public $name = "GBPCurrencyConverter";
  9. public $rates = array("USD" => 0.622846,
  10. "AUD" => 0.643478);
  11. protected $var1;
  12. private $var2;
  13. function __construct() {}
  14. function convert($currency, $amount) {
  15. return $rates[$currency] * $amount;
  16. }
  17. }
  18. if (interface_exists("ICurrencyConverter")) {
  19. echo "ICurrencyConverter interface exists.n";
  20. }
  21. $classes = get_declared_classes();
  22. echo "The following classes are available:n";
  23. print_r($classes);
  24. if (in_array("GBPCurrencyConverter", $classes)) {
  25. print "GBPCurrencyConverter is declared.n";
  26. $gbpConverter = new GBPCurrencyConverter();
  27. $methods = get_class_methods($gbpConverter);
  28. echo "The following methods are available:n";
  29. print_r($methods);
  30. $vars = get_class_vars("GBPCurrencyConverter");
  31. echo "The following properties are available:n";
  32. print_r($vars);
  33. echo "The method convert() exists for GBPCurrencyConverter: ";
  34. var_dump(method_exists($gbpConverter, "convert"));
  35. }

输出如下:

ICurrencyConverter interface exists.
The following classes are available:
Array
(
[0] => stdClass
[1] => Exception
[2] => ErrorException
[3] => Closure
[4] => DateTime
[5] => DateTimeZone
[6] => DateInterval
[7] => DatePeriod

[154] => GBPCurrencyConverter
)
GBPCurrencyConverter is declared.
The following methods are available:
Array
(
[0] => __construct
[1] => convert
)
The following properties are available:
Array
(
[name] => GBPCurrencyConverter
[rates] => Array
(
[USD] => 0.622846
[AUD] => 0.643478
)
)

2. 反射(Reflection)API

PHP通过他的Reflection类 API支持反射. 就像你在php官方手册中看到的,
Reflection类API比 introspection 方法更慷慨,提供了大量的类(classes)和(methods)
可以用来完成反射任务. ReflectionClass 是 API的主类 并用于对类,接口和方法应用反射,
并提取有关所有类组件的信息。Reflection在应用程序代码中很容易实现,像内省一样也很直观。

下面有个例子来解释 reflection使用相同的定义 ICurrencyConverter 接口
以及子类 GBPCurrencyConverter:

  1. <?php
  2. $child = new ReflectionClass("Child");
  3. $parent = $child->getParentClass();
  4. echo $child->getName() . " is a subclass of " . $parent->getName() . ".n";
  5. $reflection = new ReflectionClass("GBPCurrencyConverter");
  6. $interfaceNames = $reflection->getInterfaceNames();
  7. if (in_array("ICurrencyConverter", $interfaceNames)) {
  8. echo "GBPCurrencyConverter implements ICurrencyConverter.n";
  9. }
  10. $methods = $reflection->getMethods();
  11. echo "The following methods are available:n";
  12. print_r($methods);
  13. if ($reflection->hasMethod("convert")) {
  14. echo "The method convert() exists for GBPCurrencyConverter.n";
  15. }
  16. ?>

下面是输出:

Child is a subclass of Introspection.
GBPCurrencyConverter implements ICurrencyConverter.
The following methods are available:
Array
(
[0] => ReflectionMethod Object
(
[name] => __construct
[class] => GBPCurrencyConverter
)

  1. \[1\] => ReflectionMethod Object
  2. (
  3. \[name\] => convert
  4. \[class\] => GBPCurrencyConverter
  5. )

)

getInterfaceNames() 返回当前类实例化的接口的名字.
getParentClass() 返回一个 ReflectionClass 对象 表示这个父类或者 false(如果没有父类的话).
为了列举出 ReflectionClass 对象的名字, 你可以使用 getName() 方法, 就像你在上面的方法中看到的.

getMethods() 方法返回了一个数组的方法 还可以加一个可选参数 ReflectionMethod::IS_STATIC,IS_PUBLIC, IS_PROTECTED,IS_PRIVATE, IS_ABSTRACT, 和IS_FINAL 过率掉基于可见的方法

Reflection API 提供了一个好的实现给你反射的能力去创建更好的应用, 像 ApiGen, 虽然进一步的讨论超出了本文的目标.

总结
这篇文章里你已经看到了如何去使用 PHP的 内省函数 和 反射 API 来获取得到信息关于类, 接口, 属性, 和 方法. 获取这些信息的目的是在运行时更好地了解您的代码,并创建复杂的应用程序。

本文翻译参考来源:https://www.sitepoint.com/introspection-and-reflection-in-php/

PHP官方手册:http://php.net/manual/zh/class.reflectionclass.php

Larave反射机制:https://baijiahao.baidu.com/s?id=1574039951134516&wfr=spider&for=pc

Laravel反射控制权限:https://laravel-china.org/articles/5621/use-the-php-reflection-mechanism-to-obtain-permissions

发表评论

表情:
评论列表 (有 0 条评论,214人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Java反射内省

    反射 用一句比较白的话来概括,反射就是让你可以通过名称来得到对象(类,属性,方法)的技术。 例如我们可以通过类名来生成一个类的实例;知道了方法名,就可以调用这个方法;知道了

    相关 PHP面向对象抽象

    在oop语言中,一个类可以有一个或多个子类,而每个类都有一个公有方法做为外部代码访问其的接口。而抽象方法就是为了方便继承而引入的。 掌握2个为什么? 什么是抽象方法?