PHP 5 具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释。
其功能十分强大,经常用于高扩展的PHP框架,自动加载插件,自动生成文档,甚至可以用来扩展PHP语言。由于它是PHP內建的oop扩展,为语言本身自带的特性,所以不需要额外添加扩展或者配置就可以使用。更多内容见官方文档。
1.具体类目
1.1.ReflectionClass
主要是读取被反射类的信息,用于文档生成或检查是否包含某种信息 |
- ReflectionClass::getDocComment — 获取文档注释
- ReflectionClass::getEndLine — 获取最后一行的行数
- ReflectionClass::getInterfaces — 获取接口
- ReflectionClass::getMethods — 获取方法的数组
测试代码:
<?php
/**
* Class Demo1
*/
class Demo1 {
const NAME = 'tom';
const AGE = 18;
/**
* 测试用的方法
* @param $arg String 随便一个参数
*/
public function test($arg) {
echo "hello I am Demo1.test()," . $arg;
}
}
$demo1 = new ReflectionClass('Demo1');
print_r($demo1->getConstants()); // Array(NAME] => tom,[AGE] => 18)
print_r($demo1->getConstant('NAME')); // tom
print_r($demo1->getConstant('GENDER')); // 空白
print_r($demo1->getDocComment());
///**
// * Class Demo1
// */
$reflectionMethod = $demo1->getMethod('test');
echo $reflectionMethod->getDocComment();
///**
// * 测试用的方法
// * @param $arg String 随便一个参数
// */
print_r('test args number is : ' . $reflectionMethod->getNumberOfParameters()); // test args number is : 1
1.2 ReflectionExtension
报告了PHP扩展的有关信息,只能反射拓展的内容
- ReflectionExtension::getClasses — Gets classes
- ReflectionExtension::getClassNames — 获取类名称
- ReflectionExtension::getDependencies — 获取依赖
- ReflectionExtension::getFunctions — 获取扩展中的函数
- ReflectionExtension::getINIEntries — 获取ini配置
- ReflectionExtension::getName — 获取扩展名称
- ReflectionExtension::getVersion — 获取扩展版本号
- ReflectionExtension::info — 输出扩展信息
- ReflectionExtension::isPersistent — 返回扩展是否持久化载入
- ReflectionExtension::isTemporary — 返回扩展是否是临时载入
$reflectionExtension = new ReflectionExtension('zlib');
//var_dump($reflectionExtension->getFunctions());
var_dump($reflectionExtension->getName()); // string(4) "zlib"
//var_dump($reflectionExtension->info());
1.3 ReflectionMethod ☆☆☆☆☆
ReflectionMethod 类报告了一个方法的有关信息。
- ReflectionMethod::getModifiers — 获取方法的修饰符
- ReflectionMethod::invoke — Invoke(可变参数)
- ReflectionMethod::invokeArgs — 带参数执行(数组参数)
- ReflectionMethod::isAbstract — 判断方法是否是抽象方法
- ReflectionMethod::isConstructor — 判断方法是否是构造方法
- ReflectionMethod::isDestructor — 判断方法是否是析构方法
- ReflectionMethod::isFinal — 判断方法是否定义 final
- ReflectionMethod::isPrivate — 判断方法是否是私有方法
- ReflectionMethod::isProtected — 判断方法是否是保护方法 (protected)
- ReflectionMethod::isPublic — 判断方法是否是公开方法
- ReflectionMethod::isStatic — 判断方法是否是静态方法
- ReflectionMethod::setAccessible — 设置方法是否访问
<?php
/**
* Class Demo2
* @Author Mustard
* @Date 2020-11-27
*/
class Demo2 {
public static function test1($args1, $args2 = 'boy') {
echo 'hello ' . $args1 . ', I am a static ' . $args2 . PHP_EOL;
}
public function test2($args1, $args2 = 'boy') {
echo 'hello ' . $args1 . ', I am a ' . $args2 . PHP_EOL;
}
private function test3($args1) {
echo 'hello ' . $args1 . PHP_EOL;
}
public function test4($a1, $a2, $a3) {
print_r("$a1 + $a2 + $a3 = " . ($a1 + $a2 + $a3) . PHP_EOL);
}
}
/*************静态方法测试************/
$reflectionStaticMethod = new ReflectionMethod('Demo2', 'test1');
echo '参数个数为:' . $reflectionStaticMethod->getNumberOfParameters() . PHP_EOL; // 参数个数为:2
echo '必填参数个数为:' . $reflectionStaticMethod->getNumberOfRequiredParameters() . PHP_EOL; // 必填参数个数为:1
echo '是否是公开方法:' . ($reflectionStaticMethod->isPublic() ? '是' : '否') . PHP_EOL; // 是否是公开方法:是
echo '是否是私有方法:' . ($reflectionStaticMethod->isPrivate() ? '是' : '否') . PHP_EOL; // 是否是公开方法:否
// 如果调用的是静态方法,第一个参数(object)填写null
$reflectionStaticMethod->invoke(null, 'mustard'); //hello mustard, I am a static boy
/*************成员方法测试************/
$reflectionMethod = new ReflectionMethod('Demo2', 'test2');
$reflectionClass = new ReflectionClass('Demo2');
$newInstance = $reflectionClass->newInstance(); // 需要去弄一个实例 或者是直接new Demo2();
$reflectionMethod->invoke($newInstance, 'mustard'); //hello mustard, I am a boy
/*************多参数方法测试************/
$reflectionMethod = new ReflectionMethod('Demo2', 'test4');
$reflectionMethod->invoke($newInstance, 1, 2, 3); // 1 + 2 + 3 = 6
$reflectionMethod->invokeArgs($newInstance, [1, 2, 3]); // 1 + 2 + 3 = 6
/*************成员私有方法测试************/
$reflectionPrivateMethod = new ReflectionMethod('Demo2', 'test3');
echo '是否是私有方法:' . ($reflectionPrivateMethod->isPrivate() ? '是' : '否') . PHP_EOL; // 是否是公开方法:否
try {
$reflectionPrivateMethod->invoke($newInstance, 'mustard'); // 异常
} catch (ReflectionException $e) {
print_r($e->getMessage()); // Trying to invoke private method Demo2::test3() from scope ReflectionMethod
}
封装一个方法,输入类名、方法名及参数就可以执行:
/**
* @param string $className 类名(全类名)
* @param string $methodName 方法名
* @param array $args 参数 可选
* @return bool|mixed 返回结果,执行失败返回false
*/
function myInvoke($className, $methodName, $args = []) {
try {
$reflectionClass = new ReflectionClass($className);
$newInstance = $reflectionClass->newInstance();
$reflectionMethod = new ReflectionMethod($className, $methodName);
return $reflectionMethod->invokeArgs($newInstance, $args);
} catch (ReflectionException $e) {
print_r('ReflectionException: ' . $e->getMessage());
return false;
}
}
myInvoke('Demo2', 'test4', [1, 2, 3]);
2.项目应用
2.1.策略者模式(Strategy)
项目背景:某公园有多个售票窗口,每个窗口售票的类型不同,有不同的打折方式,如:学生票八折,VIP票五折等。通过配置文件来决定窗口类型。
Ticket.php
<?php
class Ticket {
private $price;
private $discount;
public function __construct($price) {
$this->price = $price;
}
public function getPrice() {
if (empty($this->discount))
throw new Exception('请先初始化折扣属性');
echo '原始票价为:' . $this->price . PHP_EOL;
/*
// 使用反射调用方法
$reflectionMethod = new ReflectionMethod($this->discount, 'calculate');
return $reflectionMethod->invoke($this->discount, $this->price);
*/
// 正常调用
return $this->discount->calculate($this->price);
}
public function setDiscount($discount) {
$this->discount = $discount;
}
}
Discount.php(抽象接口)
<?php
interface Discount {
public function calculate($price);
}
StudentDiscount.php(具体打折实现类)
<?php
class StudentDiscount implements Discount {
public function calculate($price) {
return $price * 0.8;
}
}
VIPDiscount.php(具体打折实现类)
<?php
class StudentDiscount implements Discount {
public function calculate($price) {
return $price * 0.8;
}
}
Client.php(客户端)
<?php
class Client {
public function sale($discount) {
print_r('sale');
$ticket = new Ticket(100.00);
$ticket->setDiscount($discount);
print_r('打折后票价为:' . $ticket->getPrice() . PHP_EOL);
}
}
config.ini(配置文件)
[system]
type_a = StudentDiscount
type_b = VIPDiscount
Test.php(测试文件)
<?php
/**
* 自动加载
* @param $class_name
*/
function __autoload($className) {
require './' . $className . '.php';
}
try {
$config = parse_ini_file('./config.ini');
$type = $config['type_a'];
$discount = (new ReflectionClass($type))->newInstance();
$client = new Client();
$client->sale($discount);
print_r('*******************' . PHP_EOL);
$type = $config['type_b'];
$discount = (new ReflectionClass($type))->newInstance();
$client = new Client();
$client->sale($discount);
} catch (Exception $e) {
print_r($e->getMessage());
}
/*
输出内容:
sale原始票价为:100
打折后票价为:80
*******************
sale原始票价为:100
打折后票价为:50
*/
参考文章:
【PHP官方手册】https://www.php.net/manual/zh/book.reflection.php
【空城里的往日时光】https://www.cnblogs.com/llljpf/p/10830651.html
【晏南风i】https://www.php.cn/blog/detail/9327.html
扫码在手机查看
您没有登录或者此篇文章不允许评论哟~~
暂无评论