`
tiandirensoon
  • 浏览: 597205 次
文章分类
社区版块
存档分类
最新评论

php 反射类简介

 
阅读更多
反射是操纵面向对象范型中元模型的API,其功能十分强大,可帮助我们构建复
杂,可扩展的应用。其用途如:自动加载插件,自动生成文档,甚至可用来扩充
PHP 语言。php 反射api 由若干类组成,可帮助我们用来访问程序的元数据或者
同相关的注释交互。借助反射我们可以获取诸如类实现了那些方法,创建一个类
的实例(不同于用new 创建),调用一个方法(也不同于常规调用),传递参数,
动态调用类的静态方法。
*
**
反射api 是php 内建的oop 技术扩展,包括一些类,异常和接口,综合使用他们
可用来帮助我们分析其它类,接口,方法,属性,方法和扩展。这些oop 扩展被
称为反射,位于php 源码/ext/reflection 目录下。
可以使用反射api 自省反射api 本身(这可能就是反射最初的意思,自己“看”自己):
<?php
Reflection::export(new ReflectionExtension('reflection'));
?>
几乎所有的反射api 都实现了reflector 接口,所有实现该接口的类都有一个export
方法,该方法打印出参数对象的相关信息。
使用get_declared_classes()获取所有php 内置类,get_declared_interfaces();
get_defined_functions();
get_defined_vars(); get_defined_constants();可获取php 接口,方法,变量,常量信
息。
**
***
反射初探:
<?php
//定义一个自定义类
class MyTestClass{
public function testFunc($para0='defaultValue0'){
}
}
//接下来反射它
foreach(get_declared_classes() as $class){
//实例化一个反射类
$reflectionClass = new ReflectionClass($class);
//如果该类是自定义类
if($reflectionClass->isUserDefined()){
//导出该类信息
Reflection::export($reflectionClass);
}
}
?>
以上片段实例如何查看自定义类的基本信息。
描述数据的数据被称为元数据,用反射获取的信息就是元数据信息,这些信息用
来描述类,接口方法等等。(元---》就是原始之意,比如元模型就是描述模型的模
型,比如UML 元模型就是描述UML 结构的模型),元数据进一步可分为硬元数
据(hard matadata)和软元数据(soft metadata),前者由编译代码导出,如类名字,
方法,参数等。
后者是人为加入的数据,如phpDoc 块,php 中的属性等。
***
****
现在商业软件很多都是基于插件架构的,比如eclipse,和visual studio,netbeans
等一些著名IDE 都是基于插件的GUI 应用。第三方或本方开发插件时,必须导入
定义好的相关接口,然后实现这些接口,最后把实现的包放在指定目录下,宿主
应用程序在启动时自动检测所有的插件实现,并加载它们。如果我们自己想实现
这样的架构也是可能的。
<?php
//先定义UI 接口
interface IPlugin {
//获取插件的名字
public static function getName();
//要显示的菜单项
function getMenuItems();
//要显示的文章
function getArticles();
//要显示的导航栏
function getSideBars();
}
//一下是对插件接口的实现
class SomePlugin implements IPlugin {
public function getMenuItems() {
//返回菜单项
return null;
}
public function getArticles() {
//返回我们的文章
return null;
}
public function getSideBars() {
//我们有一个导航栏
return array('SideBarItem');
}
//返回插件名
public static function getName(){
return "SomePlugin";
}
}
?>
php 中也有使用插件的解决方案,不像eclipse。
使用我们的插件:1.先使用get_declared_classes()获取所有已加载类。2.遍历所有
类,判断其是否实现了我们自定义的插件接口IPlugin。3.获取所有的插件实现。4.
在宿主应用中与插件交互
下面这个方法帮助我们找到实现了插件接口的所有类:
function findPlugins() {
$plugins = array();
foreach(get_declared_classes() as $class) {
$reflectionClass = new ReflectionClass($class);
//判断一个类是否实现了IPlugin 接口
if($reflectionClass->implementsInterface('IPlugin')) {
$plugins[] = $reflectionClass;
}
}
return $plugins;
}
注意到所有的插件实现是作为反射类实例返回的,而不是类名本身,或是类的实
例。因为如果使用反射来调用方法还需要一些条件判断。
判断一个类是否实现了某个方法使用反射类的hasMethod()方法。
接下来我们把所有的插件菜单项放在一个菜单上。
function integratePlugInMenus() {
$menu = array();
//遍历所有的插件实现
foreach(findPlugins() as $plugin) {
//判断插件是否实现了getMenuItems 方法
if($plugin->hasMethod('getMenuItems')) {
/*实例化一个方法实例(注意当你将类和方法看成概念时,它们就可以有实例,
就像“人”这个概念一样),该方法返回的是ReflectionMethod 的实例*/
$reflectionMethod = $plugin->getMethod('getMenuItems');
//如果方法是静态的
if($reflectionMethod->isStatic()) {
//调用静态方法,注意参数是null 而不是一个反射类实例
$items = $reflectionMethod->invoke(null);
} else {
//如果方法不是静态的,则先实例化一个反射类实例所代表的类的实例。
$pluginInstance = $plugin->newInstance();
//使用反射api 来调用一个方法,参数是通过反射实例化的对象引用
$items = $reflectionMethod->invoke($pluginInstance);
}
//合并所有的插件菜单项为一个菜单。
$menu = array_merge($menu, $items);
}
}
return $menu;
}
这里主要用到的反射方法实例的方法调用:
public mixed invoke(stdclass object, mixed args=null);
请一定搞清楚我们常规方法的调用是这种形式:$objRef->someMethod($argList...);
因为使用了反射,这时你在想调用一个方法时形式变为:
$reflectionMethodRef->invoke($reflectionClassRef,$argList...);
如果使用反射调用方法,我们必须实例化一个反射方法的实例,如果是实例方法
还要有一个实例的引用,可能还需传递必要的参数。当调用一个静态方法时,显
式传入null 作为第一参数。
对插件类实现的其他方法有类似的处理逻辑,这里不再敷述。
以下是我的一个简单测试:
<?php
/**
* 定义一个插件接口
* */
interface IPlugIn
{
/**
* getSidebars()
*
* @return 返回侧导航栏
*/
public function getSidebars();
/**
* GetName()
*
* @return 返回类名
*/
public static function GetName();
}
/*下面是对插件的实现,其实应该放在不同的文件中,甚至是不同的包中*/
class MyPlugIn implements IPlugIn
{
public function getSidebars()
{
//构造自己的导航栏
$sideBars = '<div><ul >
<li><a href="">m1</a>
</li>
<li><a href="">m2</a>
</li>
</ul>
</div>';
return $sideBars;
}
public static function GetName()
{
return 'MyPlugIn';
}
}
//第二个插件实现;
class MyPlugIn2 implements IPlugIn
{
public function getSidebars()
{
//构造自己的导航栏
$sideBars = '<div><ul >
<li><a href="">mm1</a>
</li>
<li><a href="">mm2</a>
</li>
</ul>
</div>';
return $sideBars;
}
public static function GetName()
{
return 'MyPlugIn2';
}
}
//在宿主程序中使用插件
class HostApp
{
public function initAll()
{
// 初始化各个部分
echo "yiqing95.";
$this->renderAll();
}
//渲染GUI 格部分
function renderAll(){
$rsltSidebars="<table>";
foreach($this->integrateSidebarsOfPlugin() as $sidebarItem){
$rsltSidebars.="<tr><td>$sidebarItem</td></tr>";
}
$rsltSidebars.="</table>";
echo $rsltSidebars;
}
/*加载所有的插件实现:*/
protected function findPlugins()
{
$plugins = array();
foreach (get_declared_classes() as $class) {
$reflectionClass = new ReflectionClass($class);
if ($reflectionClass->implementsInterface('IPlugin')) {
$plugins[] = $reflectionClass;
}
}
return $plugins;
}
/**加载组装所有插件实现***/
protected function integrateSidebarsOfPlugin()
{
$sidebars = array();
foreach ($this->findPlugins() as $plugin) {
if ($plugin->hasMethod('getSidebars')) {
$reflectionMethod = $plugin->getMethod('getSidebars');
if ($reflectionMethod->isStatic()) {
$items = $reflectionMethod->invoke(null);
} else {
$pluginInstance = $plugin->newInstance();
$items =
$reflectionMethod->invoke($pluginInstance) ;
}
}
//$sidebars = array_merge($sidebars, $items);
$sidebars[]=$items;
}
return $sidebars;
}
}
//运行程序:
$entryClass =new HostApp();
$entryClass->initAll();
?>
****
××××
$reflectionClass = new ReflectionClass("IPlugIn");
echo $reflectionClass-> getDocComment();
这段代码可以帮助我们获取类的文档注释,一旦我们获取了类的注释内容我们就
可以扩展我们的类功能,比如先获取注释,然后分析注释使用docblock tokenizer
『pecl 扩展』,或使用自带的Tokenizer 类又或者使用正则表达式,字符串函数来
解析注释文档,你可以在注释中加入任何东西,包括指令,在使用反射调用前可
判断这些通过注释传递的指令或数据:
<?php
//"分析相关的注释数据"
analyse($reflectionClass-> getDocComment());//analyse 是自己定义的!!!
//根据分析的结果来执行方法,或者传递参数等
if(xxxx){
$reflectionMethod->invoke($pluginInstance) ;
}
?>
因为注释毕竟是字符串,可以使用任何字符串解析技术,提取有用的信息,再根
据这些信息来调用方法,就是说程序的逻辑不光可由方法实现决定,还可能由注
释决定(前提是你使用了反射,注释格式严格有要求)。
××××
*****
反射api 和其他类一样可被继承扩展,所以我们可以为这些api 添加自己的功能。
结合自定义注释标记。就是以@开头的东东,标注(Java 中称为annotation),.net
中称为属性attribute(或称为特性)。然后扩展Reflection 类,就可以实现强大的
扩展功能了。
值得一提的是工厂方法设计模式(GOF 之一),也常使用反射来实例化对象,下
面是示例性质的伪码:
Class XXXFactory{
function getInstance($className){
$reflectionClass =new ReflectionClass($className);
return $reflectionClass->newInstance();
}
//使用接口的那个类实现,可能来自配置文件
function getInstance(){
$pathOfConfig = "xxx/xx/XXXImplement.php";
$className= Config->getItem($pathOfClass,'SomeClassName');
return $this->getInstance($className);
}
}
*****
分享到:
评论

相关推荐

    php 反射简单例子

    php 反射简单例子

    php 反射详细实例

    详细介绍了php如何利用反射机制调用类的函数,包括调用静态函数和非静态函数用法的区别

    php反射方法调用执行类中的私有方法.zip

    介绍一篇关于PHP通过反射方法调用执行类中的私有方法,希望这篇教程能够帮助到各位朋友,有兴趣的可以进来看看。具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。

    PHP反射类ReflectionClass和ReflectionObject的使用方法

    PHP中的扩展反射类,该扩展用来分析php程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。看一个这样的问题,php类的成员变量没有在类中声明,而是在函数中声明,有什么不同?复制代码 代码如下:...

    PHP反射介绍

    PHP,是英文超级文本预处理语言Hypertext Preprocessor的缩写。PHP 是一种 HTML 内嵌式的语言,是一种在服务器端执行的嵌入HTML文档的脚本语言,语言的风格有类似于C语言,被广泛的运用... 该文档是介绍PHP反射机制的。

    PHP的反射类ReflectionClass、ReflectionMethod使用实例

    主要介绍了PHP的反射类ReflectionClass、ReflectionMethod使用实例,本文同时介绍了反射是什么、反射可以做哪些事情,并给出一个具体例子,是一篇不错的入门文章,需要的朋友可以参考下

    PHP的反射动态获取类方法、属性、参数操作示例

    主要介绍了PHP的反射动态获取类方法、属性、参数操作,结合实例形式分析了PHP反射的功能、原理及基于反射动态获取类方法、属性、参数相关操作技巧,需要的朋友可以参考下

    PHP类的反射用法实例

    本文实例讲述了PHP类的反射用法。分享给大家供大家参考。具体实现方法如下: 该例实现对于每个频道获取相应的类来执行相应的操作。具体如下: 复制代码 代码如下:foreach($this-&gt;chs as $ch) {  $className = $this...

    php+mysql数据库类

    php 连接mysql 数据类 很好用的一个数据库类 包括getall() getone query 方法

    浅析PHP类的反射来实现依赖注入过程

    主要介绍了PHP类的反射来实现依赖注入过程以及相关知识点分享,对此有兴趣的朋友跟着小编学习下吧。

    PHP面向对象程序设计之类与反射API详解共5页.pdf

    PHP面向对象程序设计之类与反射API详解共5页.pdf.zip

    PHP使用反射机制实现查找类和方法的所在位置

    本文实例讲述了PHP使用反射机制实现查找类和方法的所在位置。分享给大家供大家参考,具体如下: //参数1是类名,参数2是方法名 $func = new ReflectionMethod('UnifiedOrder_pub', 'getPrepayId'); //从第几行开始 $...

    php反射api.pdf

    php反射api.pdf

    php反射学习之不用new方法实例化类操作示例

    本文实例讲述了php反射学习之不用new方法实例化类操作。分享给大家供大家参考,具体如下: 上一篇php反射入门示例简单介绍了 php 反射的几个常见类的使用方法,但是用反射能做些什么,你可能还是想象不到, 下面我...

    php反射类ReflectionClass用法分析

    主要介绍了php反射类ReflectionClass用法,结合实例形式较为详细的分析了php反射类的概念、功能与具体使用方法,需要的朋友可以参考下

    PHP反射原理与用法深入分析

    本文实例讲述了PHP反射原理与用法。分享给大家供大家参考,具体如下: 说到反射,实际上包含两个概念: 检视 introspection 判断类、方法是否存在,父子类关系,调用关系等,检视的函数文档 反射 Reflection 获取...

    PHP反射机制原理与用法详解

    本文实例讲述了PHP反射机制原理与用法。分享给大家供大家参考,具体如下: 反射 面向对象编程中对象被赋予了自省的能力,而这个自省的过程就是反射。 反射,直观理解就是根据到达地找到出发地和来源。比如,一个...

    PHP通过反射动态加载第三方类和获得类源码的实例

    主要介绍了PHP通过反射动态加载第三方类和获得类源码的方法,一般在解析XML文件时会用到,需要的朋友可以参考下

Global site tag (gtag.js) - Google Analytics