您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

简单学习PHP中的反射

2019/5/23 8:04:08发布104次查看

和java一样php中也提供了一套完整的反射api,何为反射?以前我们是先写类,再在类中添加各种方法和属性,最后实例化一个类对象调用属性和方法。那有我们没有办法只通过这个实例对象获取到关于这个类的全部信息呢,包括有哪些方法和属性它们分别在多少行?答案就是反射。
几个常用的反射api的类
reflectionclassclass people {
protected $name = foo;
protected $age = 18;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public function func1()
{
echo fun1;
}
public function tostring()
{
echo name: $this->name, age: $this->age . php_eol;
}
}
class student extends people {
public $major;
public function __construct($name, $age, $major)
{
$this->major = $major;
parent::__construct($name, $age);
}
public function tostring()
{
echo name: $this->name, age: $this->age, major: $this->major . php_eol;
}
}
$reflect = new reflectionclass(student);
// 也可以传一个实例对象
// $reflect = new reflectionclass(new student(jason,21,cs));
reflection::export($reflect);
输出结果如下:
class [ class student extends people ] {
@@ /…/demo1.php 18-31
- constants [0] {
}
- static properties [0] {
}
- static methods [0] {
}
- properties [3] {
property [ public $major ]
property [ protected $name ]
property [ protected $age ]
}
- methods [2] {
method [ public method __construct ] {
@@ /…/demo1.php 21 - 25
- parameters [3] {
parameter #0 [ $name ]
parameter #1 [ $age ]
parameter #2 [ $major ]
}
}
method [ public method tostring ] {
@@ /…/demo1.php 27 - 30
}
}
}
可以看到,reflection::export几乎提供了student类的所有信息,包括属性和方法的访问控制状态,每个方法需要的参数以及每个方法在脚本中的位置,和var_dump相比,在使用var_dump前总是需要实例化一个对象,而且无法提供那么多详细信息。var_dump输出如下:
object(student)#1 (3) {
[major]=>
string(2) cs
[name:protected]=>
string(5) jason
[age:protected]=>
int(21)
}
虽然var_dump和print_r是打印数据的利器,但对于类和函数,反射api提供了更高层次的功能。同时,reflectionclass还提供其他有用的方法:
// 获取构造函数
$reflect->getconstructor();
object(reflectionmethod)#2 (2) {
[name]=>
string(11) __construct
[class]=>
string(7) student
}
// 获取类名
$reflect->getname();
string(7) student”
// 判断接口类
$reflect->isinterface(); // false
// 判断抽象类
$reflect->isabstract(); // false
// 类开始行
$reflect->getstartline();
// 类结束行
$reflect->getendline();
详细的可以看官方文档: /roave/betterreflection
betterreflection现在我们来简单学习下,这个包如何使用。
1. 安装
$ composer require roave/better-reflection
2. 使用
创建reflectionclass
use roave\betterreflection\reflection\reflectionclass;
$classinfo = reflectionclass::createfromname(student::class); // 通过类名创建
// 或者
$classinfo = reflectionclass::createfrominstance(new student(daniel,18,math)); // 通过实例创建
上面的静态初始化方式就等于下面:
use roave\betterreflection\betterreflection;
$classinfo = (new betterreflection)->classreflector()->reflect(student::class);
我们查看静态构造器createfromname的实现,会发现也是先实例化一个betterreflection再进行反射的:
public static function createfromname(string $classname) : self
{
return (new betterreflection())->classreflector()->reflect($classname);
}
获取reflectionmethod、reflectionparameter和reflectionproperty也是一样一样的:
use roave\betterreflection\reflection\reflectionmethod;
use roave\betterreflection\reflection\reflectionparameter;
use roave\betterreflection\reflection\reflectionproperty;
$methodinfo = reflectionmethod::createfromname(student::class,tostring);
$methodinfo = reflectionmethod::createfrominstance($student,tostring);

3. betterreflection中的sourcelocator
sourcelocator的作用是根据不同的源码类型(有通过字符串传来的类、composer自动加载的类、一个指定文件名的类等), 得到locatedsource对象的(用于ast),这个对象指向要反射的类,主要就以下几个方法:
class locatedsource
{
/** @var string */
private $source;
/** @var string|null */
private $filename;
/**
* @throws invalidargumentexception
* @throws invalidfilelocation
*/
public function __construct(string $source, string $filename) {…}
public function getsource() : string {…}
public function getfilename() : string {…}
/**
* is the located source in php internals
*/
public function isinternal() : bool {…}
public function getextensionname() : string {…}
/**
* is the located source produced by eval() or \function_create()
*/
public function isevaled() : bool {…}
}
针对不同的情况,比如单个文件、源码字符串、闭包等,又衍生出了多种sourcelocator:
composersourcelocator: 这应该是最常用的了,它使用composer自带的autoload来定位singlefilesourcelocator: 通过指定文件名来定位stringsourcelocator: 直接使用定义类的字符串autoloadsourcelocator: 使用php内置的autoloader来定位,默认会使用这个定位器evaledcodesourcelocator: 用于eval()创建的代码phpinternalsourcelocator: 用于php原生代码anonymousclassobjectsourcelocator: 用于php中的匿名类closuresourcelocator: 用于闭包aggregatesourcelocator: 合并多个sourcelocatorfileiteratorsourcelocator: 用于可迭代的splfileinfo实例数组directoriessourcelocator: 用于文件夹的情况,包括子文件夹如何使用这这些locator?
1. 使用composer的autoload加载
use roave\betterreflection\betterreflection;
use roave\betterreflection\reflector\classreflector;
use roave\betterreflection\sourcelocator\type\composersourcelocator;
$classloader = require vendor/autoload.php;
$astlocator = (new betterreflection())->astlocator();
$reflector = new classreflector(new composersourcelocator($classloader, $astlocator));
$reflectionclass = $reflector->reflect(foo\bar\myclass);
echo $reflectionclass->getshortname(); // myclass
echo $reflectionclass->getname(); // foo\bar\myclass
echo $reflectionclass->getnamespacename(); // foo\bar
2. 使用定义类的字符串加载
use roave\betterreflection\betterreflection;
use roave\betterreflection\reflector\classreflector;
use roave\betterreflection\sourcelocator\type\stringsourcelocator;
$code =
$astlocator = (new betterreflection())->astlocator();
$reflector = new classreflector(new stringsourcelocator($code, $astlocator));
$reflectionclass = $reflector->reflect(foo);
echo $reflectionclass->getshortname(); // foo
3. 通过指定php文件名来加载
use roave\betterreflection\betterreflection;
use roave\betterreflection\reflector\classreflector;
use roave\betterreflection\sourcelocator\type\singlefilesourcelocator;
$astlocator = (new betterreflection())->astlocator();
$reflector = new classreflector(new singlefilesourcelocator(path/to/myapp/myclass.php, $astlocator));
$reflectionclass = $reflector->reflect(myapp\myclass);
echo $reflectionclass->getshortname(); // myclass
echo $reflectionclass->getname(); // myapp\myclass
echo $reflectionclass->getnamespacename(); // myapp
这种方式虽然传的是一个文件,但是在singlefilesourcelocator::createlocatedsource()方法中会使用file_get_contents转换成字符串。
protected function createlocatedsource(identifier $identifier) : locatedsource
{
return new locatedsource(
file_get_contents($this->filename),
$this->filename
);
}
其他的几个locator就不多介绍了。最后说一下如何反射一个闭包:
$myclosure = function () {
echo hello world!\n;
};
$functioninfo = reflectionfunction::createfromclosure($myclosure);
$functioninfo->isclosure(); // true
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product