您的位置:首页 > 编程语言 > PHP开发

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

2017-08-15 21:37 761 查看


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), 父类的名字等等.

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

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

<?php
class Introspection
{
public function description() {
echo "I am a super class for the Child class.n";
}
}

class Child extends Introspection
{
public function description() {
echo "I'm " . get_class($this) , " class.n";
echo "I'm " . get_parent_class($this) , "'s child.n";
}
}

if (class_exists("Introspection")) {
$introspection = new Introspection();
echo "The class name is: " . get_class($introspection) . "n";
$introspection->description();
}

if (class_exists("Child")) {
$child = new Child();
$child->description();

if (is_subclass_of($child, "Introspection")) {
echo "Yes, " . get_class($child) . " is a subclass of Introspection.n";
}
else {
echo "No, " . get_class($child) . " is not a subclass of Introspection.n";
}
}
?>

输出如下:

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类的定义,

并输出上面列出的函数提取的信息。 与第一个例子一样,我将首先列出这些函数,然后显示一些代码。

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

我们看个栗子:

<?php
interface ICurrencyConverter
{
public function convert($currency, $amount);
}

class GBPCurrencyConverter implements ICurrencyConverter
{
public $name = "GBPCurrencyConverter";
public $rates = array("USD" => 0.622846,
"AUD" => 0.643478);
protected $var1;
private $var2;

function __construct() {}

function convert($currency, $amount) {
return $rates[$currency] * $amount;
}
}

if (interface_exists("ICurrencyConverter")) {
echo "ICurrencyConverter interface exists.n";
}

$classes = get_declared_classes();
echo "The following classes are available:n";
print_r($classes);

if (in_array("GBPCurrencyConverter", $classes)) {
print "GBPCurrencyConverter is declared.n";

$gbpConverter = new GBPCurrencyConverter();

$methods = get_class_methods($gbpConverter);
echo "The following methods are available:n";
print_r($methods);

$vars = get_class_vars("GBPCurrencyConverter");
echo "The following properties are available:n";
print_r($vars);

echo "The method convert() exists for GBPCurrencyConverter: ";
var_dump(method_exists($gbpConverter, "convert"));
}

输出如下:

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:

<?php
$child = new ReflectionClass("Child");
$parent = $child->getParentClass();
echo $child->getName() . " is a subclass of " . $parent->getName() . ".n";

$reflection = new ReflectionClass("GBPCurrencyConverter");
$interfaceNames = $reflection->getInterfaceNames();
if (in_array("ICurrencyConverter", $interfaceNames)) {
echo "GBPCurrencyConverter implements ICurrencyConverter.n";
}

$methods = $reflection->getMethods();
echo "The following methods are available:n";
print_r($methods);

if ($reflection->hasMethod("convert")) {
echo "The method convert() exists for GBPCurrencyConverter.n";
}
?>


下面是输出:

Child is a subclass of Introspection.

GBPCurrencyConverter implements ICurrencyConverter.

The following methods are available:

Array

(

    [0] => ReflectionMethod Object

        (

            [name] => __construct

            [class] => GBPCurrencyConverter

        )

    [1] => ReflectionMethod Object

        (

            [name] => convert

            [class] => GBPCurrencyConverter

        )

)

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  php 反射