首頁  >  文章  >  後端開發  >  php反射API 簡單教程

php反射API 簡單教程

伊谢尔伦
伊谢尔伦原創
2017-07-01 10:40:301086瀏覽

說起反射ApI,自我感覺PHP中的反射ApI和java中的java.lang.reflect套件差不多,都是由可以列印和分析類別成員屬性、方法的一組內建類別組成的。可能你已經學過物件函數例如:get_class_vars()但是使用反射API會更加的靈活、輸出資訊會更加詳細。

  首先我們需要知道,反射API不僅僅是用來檢查類別的,它本身包括一組類,用來完成各種功能:常用的類別如下:

Reflection類別 #可以列印類別的基本訊息,(透過提供的靜態export()函數)
ReflectionMethod類別 #見名知意,列印類別方法、得到方法的具體資訊等
ReflectionClass類別 用於得到類別訊息,例如得到類別包含的方法,類別本的屬性,是不是抽象類等
ReflectionParameter類別 #顯示參數的訊息,可以動態得到已知方法的傳參情況
ReflectionException類別 # 用於顯示錯誤訊息
ReflectionExtension類別 得到PHP的擴充訊息,可以判斷擴充是否存在等
#

 

 







傳統的列印類別資訊與反射APi的差異

下面是一段我自己寫的參數程序,用於演示反射的使用:

<?php

class Person
{
    //成员属性
    public $name;
    public $age; 

    //构造方法
    public function construct($name, $age)
    {
        $this->name = $name;
        $this->age = $age;
    }

    //成员方法
    public function set_name($name)
    {
        $this->$name = $name;
    }

    public function get_name()
    {
        return $this->$name;
    }

    public function get_age()
    {
        return $this->$age;
    }

    public function get_user_info()
    {
        $info = &#39;姓名:&#39; . $this->name;
        $info .= &#39; 年龄:&#39; . $this->age;
        return $info;
    }
}

class Teacher extends Person
{
    private $salary = 0;

    public function construct($name, $age, $salary)
    {
        parent::construct($name, $age);
        $this->salary = $salary;
    }

    public function get_salary()
    {
        return $this->$salary;
    }

    public function get_user_info()
    {
        $info = parent::get_user_info();
        $info .= " 工资:" . $this->salary;
        return $info;
    }
}

class Student extends Person
{
    private $score = 0;

    public function construct($name, $age, $score)
    {
        parent::construct($name, $age);
        $this->score = $score;
    }

    public function get_score()
    {
        return $this->score;        
    }

    public function get_user_info()
    {
        $info = parent::get_user_info();
        $info .= " 成绩:" . $this->score;
        return $info;
    }
}

header("Content-type:text/html;charset=utf8;");
$te_obj = new Teacher(&#39;李老师&#39;, &#39;36&#39;, &#39;2000&#39;);
$te_info = $te_obj->get_user_info();

$st_obj = new Student(&#39;小明&#39;, &#39;13&#39;, &#39;80&#39;);
$st_info = $st_obj->get_user_info();

我們先用var_dump();打印類別的信息,如下所示,可以看出只是打印出類的簡單訊息,甚至連方法也沒有,所以從這樣的訊息中看不出其他游泳的訊息。

var_dump(

$te_obj);

object(Teacher)#1 (3) {
      ["salary":"Teacher":private]=>
          string(4) "2000"
      ["name"]=>
          string(9) "李老师"
      ["age"]=>
          string(2) "36"
}

  Reflection::export($obj);

#  我們利用Reflection提供的內建方法export來列印訊息,如下所示:

  列印出的資訊比較完整,包括成員屬性,成員方法,類別的基本訊息,檔案路徑,方法訊息,方法屬性,傳參情況,所在檔案的行數等等。比較全面的展示了類的資訊。可以看出var_dump()或print_r只能顯示類的簡要信息,好多信息根本顯示不出來,所以他們只能做簡單的調試之用,反射Api則提供的類更多的信息,可以很好地幫助我們知道呼叫類別的情況,這對寫接口,特別是呼叫別人的接口提供了極大的便利。如果出了問題,也可以幫忙調試。

object(Teacher)#1 (3) {
      ["salary":"Teacher":private]=>
          string(4) "2000"
      ["name"]=>
          string(9) "李老师"
      ["age"]=>
          string(2) "36"
}
Class [  class Person ] {
      @@ /usr/local/www/phptest/oop/reflaction.php 3-38
      - Constants [0] {
      }
      - Static properties [0] {
      }
      - Static methods [0] {
 }
  - Properties [2] {
        Property [  public $name ]
        Property [  public $age ]
  }

  - Methods [5] {
    Method [  public method construct ] {
      @@ /usr/local/www/phptest/oop/reflaction.php 10 - 14

      - Parameters [2] {
        Parameter #0 [  $name ]

.....

反射API的具體使用:#  看過框架原始碼的同學都知道框架都可以載入第三方的插件、類別庫等等。下面這個例子咱們借助反射APi簡單實現這個功能,該例子原型是我從書上學習的,我理解後按照自己的思路寫了一套:要實現的功能:用一個類去動態的遍歷調用Property類對象,類別可以自由的載入其他的類別的方法,而不用吧類別嵌入到已有的程式碼,也不用手動去呼叫類別庫的程式碼。     約定:每個類別要包含work方法,可以抽象化一個介面。可以把每個類別的資訊放在檔案中,相當於各個類別庫訊息,透過類別保存的Property類別庫的對應對象,然後呼叫每個類別庫的work方法。

  以下是基礎程式碼:

###
/*属性接口*/
interface Property
{
    function work();
}

class Person
{
    public $name;
    public function construct($name)
    {
        $this->name = $name;
    }
}

class StudentController implements Property
{
    //set方法,但需要Person对象参数
    public function setPerson(Person $obj_person)
    {
        echo &#39;Student &#39; . $obj_person->name;
    }

    //work方法简单实现
    public function work()
    {
        echo &#39;student working!&#39;;
    }
}

class EngineController implements Property
{
    //set方法
    public function setWeight($weight)
    {
        echo &#39;this is engine -> set weight&#39;;
    }

    public function setPrice($price)
    {
        echo "this is engine -> set price";
    }

    //work方法简单实现
    public function work()
    {
        echo &#39;engine working!&#39;;
    }
}
#######    這裡定義了兩個相似類別實作Property接口,同時都簡單實作work()方法StudentController類別稍微不同,參數需要Person對象,同時我們可以使用檔案來保存各個類別的訊息,我們也可以用成員屬性來代替。 ######
class Run
{
    public static $mod_arr = [];
    public static $config = [
        &#39;StudentController&#39; => [
            &#39;person&#39; => &#39;xiao ming&#39;
        ],
        &#39;EngineController&#39;  => [
            &#39;weight&#39; => &#39;500kg&#39;,
            &#39;price&#39;  => &#39;4000&#39;
        ]
    ];

    //加载初始化
    public function construct()
    {
        $config = self::$config;
        //用于检查是不是实现类
        $property = new ReflectionClass(&#39;Property&#39;);
        foreach ($config as $class_name => $params) {
            $class_reflect = new ReflectionClass($class_name);
            if(!$class_reflect->isSubclassOf($property)) {//用isSubclassOf方法检查是否是这个对象
                echo &#39;this is  error&#39;;
                continue;
            }

            //得到类的信息
            $class_obj = $class_reflect->newInstance();
            $class_method = $class_reflect->getMethods();

            foreach ($class_method as $method_name) {
                $this->handle_method($class_obj, $method_name, $params);
            }
            array_push(self::$mod_arr, $class_obj);
        }
    }

    //处理方法调用
    public function handle_method(Property $class_obj, ReflectionMethod $method_name, $params)
    {
        $m_name = $method_name->getName();
        $args = $method_name->getParameters();

        if(count($args) != 1 || substr($m_name, 0, 3) != &#39;set&#39;) {    
            return false;
        }
        //大小写转换,做容错处理
        $property = strtolower(substr($m_name, 3));
     
        if(!isset($params[$property])) {
            return false;
        }

        $args_class = $args[0]->getClass();
        echo &#39;<pre class="brush:php;toolbar:false">&#39;;
        if(empty($args_class)) {
            $method_name->invoke($class_obj, $params[$property]); //如果得到的类为空证明需要传递基础类型参数
        } else {
            $method_name->invoke($class_obj, $args_class->newInstance($params[$property])); //如果不为空说明需要传递真实对象
        }
    }
}

//程序开始
new Run();
######  到此程式結束,Run啟動會自動呼叫建構方法,初始化要載入類別庫的其他成員屬性,包括初始化和執行對應方法操作,這裡只是完成了對應的set方法。其中###$mod_arr屬性保存了所有呼叫類別的對象,每個對象包含數據,可以遍歷包含的對象來以此呼叫work()方法。 ###############  程式只做輔助理解反射PAI用,各個功能沒有完善,裡面用到了很多反射API的類,方法,下面會有各個方法的總結。 ##################反射API###提供的常用類別和函數:###############下面提供的函數是常用的函數,不是全部,有的函數根本用不到,所以我們有往撒謊那個寫,想看全部的可以到網上搜一下,比較多。提供的這組方法沒有必要背下來,用到的時候可以查看。 ######
1:Reflection
  public static export(Reflector r [,bool return])//打印类或方法的详细信息
  public static  getModifierNames(int modifiers)  //取得修饰符的名字

2:ReflectionMethod:
    public static string export()                       //打印该方法的信息
    public mixed invoke(stdclass object, mixed* args)   //调用对应的方法
    public mixed invokeArgs(stdclass object, array args)//调用对应的方法,传多参数
    public bool isFinal()        //方法是否为final
    public bool isAbstract()     //方法是否为abstract
    public bool isPublic()       //方法是否为public
    public bool isPrivate()      //方法是否为private
    public bool isProtected()    //方法是否为protected
    public bool isStatic()       //方法是否为static
    public bool isConstructor()  //方法是否为构造函数

3:ReflectionClass:
    public static string export()  //打印类的详细信息
    public string getName()        //取得类名或接口名
    public bool isInternal()       //类是否为系统内部类
    public bool isUserDefined()    //类是否为用户自定义类
    public bool isInstantiable()   //类是否被实例化过
    public bool hasMethod(string name)  //类是否有特定的方法
    public bool hasProperty(string name)//类是否有特定的属性
    public string getFileName()         //获取定义该类的文件名,包括路径名
    public int getStartLine()           //获取定义该类的开始行
    public int getEndLine()             //获取定义该类的结束行
    public string getDocComment()       //获取该类的注释
    public ReflectionMethod getConstructor()           //取得该类的构造函数信息
    public ReflectionMethod getMethod(string name)     //取得该类的某个特定的方法信息
    public ReflectionMethod[] getMethods()             //取得该类的所有的方法信息
    public ReflectionProperty getProperty(string name) //取得某个特定的属性信息
    public ReflectionProperty[] getProperties()        //取得该类的所有属性信息
    public array getConstants()                        //取得该类所有常量信息
    public mixed getConstant(string name)              //取得该类特定常量信息
    public ReflectionClass[] getInterfaces()           //取得接口类信息
    public bool isInterface()  //测试该类是否为接口
    public bool isAbstract()   //测试该类是否为抽象类

4:ReflectionParameter:
    public static string export()     //导出该参数的详细信息
    public string getName()           //取得参数名
    public bool isPassedByReference() //测试该参数是否通过引用传递参数
    public ReflectionClass getClass() //若该参数为对象,返回该对象的类名
    public bool isArray()             //测试该参数是否为数组类型
    public bool allowsNull()          //测试该参数是否允许为空
    public bool isOptional()          //测试该参数是否为可选的,当有默认参数时可选
    public bool isDefaultValueAvailable() //测试该参数是否为默认参数
    public mixed getDefaultValue()        //取得该参数的默认值

5:ReflectionExtension类
    public static  export()    //导出该扩展的所有信息
    public string getName()    //取得该扩展的名字
    public string getVersion() //取得该扩展的版本
    public ReflectionFunction[] getFunctions()   //取得该扩展的所有函数
    public array getConstants()  //取得该扩展的所有常量
    public array getINIEntries() //取得与该扩展相关的,在php.ini中的指令信息
}

以上是php反射API 簡單教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn