php的動(dòng)態(tài)代理和反射

面向?qū)ο蟮母呒?jí)語(yǔ)言都應(yīng)該提供了反射機(jī)制,可以動(dòng)態(tài)的獲取類的信息,否則語(yǔ)言就缺少靈活性,很多需求無(wú)法完成,php的反射相當(dāng)于iOS里面的運(yùn)行時(shí)方法。iOS的運(yùn)行系統(tǒng)提供了一系列的C語(yǔ)言方法動(dòng)態(tài)的獲取類的信息,處理消息轉(zhuǎn)發(fā),php也提供了類似的實(shí)現(xiàn),相比iOS使用更簡(jiǎn)便,下面是幾個(gè)案例。

  1. 獲取函數(shù)的信息
<?php
/**
 * Created by PhpStorm.
 * User: wangguodong
 * Date: 17/3/2
 * Time: 下午10:44
 */

/**
 * 這是testfun的注釋
 */
function testfun($name = 'test'){
    echo "this is a $name method";
    return 'a';
}

testfun();
//通過(guò)一個(gè)函數(shù)名初始化一個(gè)函數(shù)反射對(duì)象,取獲取函數(shù)的相關(guān)信息
$ref_fun = new ReflectionFunction('testfun');
//函數(shù)的所在的文件
echo '<br>函數(shù)的文件位置是:'.$ref_fun->getFileName();
//獲取函數(shù)的開(kāi)始行編號(hào)
echo '<br>函數(shù)的起始位置是:'.$ref_fun->getStartLine();
//獲取函數(shù)末尾的編號(hào)
echo '<br>函數(shù)的結(jié)束位置是:'.$ref_fun->getEndLine();
//函數(shù)的注釋
echo '<br>函數(shù)的注釋是:'.$ref_fun->getDocComment();
//獲取參數(shù)的個(gè)數(shù)
echo '<br>函數(shù)的參數(shù)個(gè)數(shù)是:'.$ref_fun->getNumberOfParameters();
//獲取具體的參數(shù)信息
echo '<br>函數(shù)的參數(shù)是:';print_r($ref_fun->getParameters());
//函數(shù)的返回值 --這里提示這個(gè)方法不存在
echo '<br>函數(shù)的返回值是:'.$ref_fun->getReturnType();

//如果反射一個(gè)不存在的函數(shù),會(huì)拋出一個(gè)異常,應(yīng)該try catch 使用
try{
    $ref_nfun = new ReflectionFunction('no_exist');
}catch (ReflectionException $e){
    echo $e->getMessage();
}

2.類的信息

class Person{

    public $name,$age,$sex;
    static function show($name,$age,$sex='男'){
        echo "姓名:$name,年齡:$age,性別:$sex";
    }
    function say($content){
        echo "我想說(shuō)的是:$content";
    }
    function eat($food= 'apple'){

    }
}
$per = new Person();

$ref = new ReflectionClass('Person');//參數(shù)可以是類名,或者類的實(shí)例
//獲取類里面的所有方法
$class_methods = $ref->getMethods();
//是一個(gè)數(shù)組,每個(gè)對(duì)象包含了方法名和所屬類
echo '<br/>';
echo "<pre>";print_r($class_methods);echo "<pre>";
//是否擁有某個(gè)方法
$has_method = $ref->hasMethod('say');
//獲取某個(gè)方法的信息
$some_method = new ReflectionMethod('Person','say');
$some_method->isPrivate();//判斷是否私有,還有static,public
//方法的調(diào)用,
if ($some_method->isPublic()&&!$some_method->isAbstract()) {

    if ($some_method->isStatic()){
        //靜態(tài)方法第一個(gè)參數(shù)是null,后面參數(shù)寫(xiě)方法的參數(shù),可以傳遞一個(gè)或者多個(gè),并且這個(gè)方法可以接受數(shù)量可變的參數(shù)。
        /*
         * * The object to invoke the method on. For static methods, pass
         * null to this parameter.
         * </p>
         * @param mixed $parameter [optional] <p>
         * Zero or more parameters to be passed to the method.
         * It accepts a variable number of parameters which are passed to the method.
         * </p>
         */
        $some_method->invoke(null,'zhangsan','23');
    }
    else {
        //非靜態(tài)方法第一個(gè)參數(shù)傳遞一個(gè)對(duì)象
        $some_method->invoke($per,'生活真好');
    }
}
}
  1. 動(dòng)態(tài)代理

消息的轉(zhuǎn)發(fā),交給其他類處理,iOS可以通過(guò)delegate實(shí)現(xiàn),也可以在運(yùn)行時(shí)通過(guò)相應(yīng)的方法轉(zhuǎn)發(fā)。

//調(diào)用B的show方法時(shí)候去調(diào)用A的show方法
class A{
    function show(){
        echo "classA的show方法";
    }
}
class B{
    private $obj;
    function __construct(){
        $this->obj = new A();
    }
    function __call($name, $arguments)
    {
         $ref = new ReflectionClass($this->obj);
         if ($ref->hasMethod($name)){
             $method = $ref->getMethod($name);
             if ($method->isPublic()&&!$method->isAbstract()&&count($arguments)){
                 if ($method->isStatic()){
                     $method->invoke(null);
                 }
                 else{
                     $method->invoke($this->obj);
                 }
             }
         }
    }
}
  1. 插件案例
include_once __DIR__."/plugin.php";
function get_plugin_menus(){
    $menus = array();
    $all_class = get_declared_classes();//獲取所有的類
    foreach ($all_class as $cls){
        $ref_cls = new ReflectionClass($cls);
        if ($ref_cls->implementsInterface('Plugin')){//是否實(shí)現(xiàn)了某個(gè)接口
            if ($ref_cls->hasMethod('showMenu')){
                $method = $ref_cls->getMethod("showMenu");
                if ($method->isStatic()){
                    $method->invoke(null);
                }
                else{
//                    $method->invoke(new $cls());//這樣獲取類
                    $instance = $ref_cls->newInstance();
                    $menu = $method->invoke($instance);
                }
            }
        }
        $menus = array_merge($menus,$menu);
    }
    return $menus;
}
echo "<pre>";get_plugin_menus();echo "<pre>";

interface Plugin{
    function showMenu();
}
class MyPlugin implements Plugin{

    function showMenu()
    {
        $menu = array(
            array(
                'name' => 'menu1', 'link' => 'index.php?act=link1'
            ),
            array(
                'name' => 'menu2', 'link' => 'index.php?act=link2'
            )
        );
        return $menu;
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,045評(píng)論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,329評(píng)論 4 61
  • 曾幾何時(shí),手機(jī)走進(jìn)人們的生活,改變著傳統(tǒng)的聯(lián)系方式,原來(lái)當(dāng)面可以說(shuō)的事情現(xiàn)在可以通過(guò)手機(jī)和短信留言來(lái)完成,曾...
    偉嘉豪閱讀 242評(píng)論 0 1
  • 這個(gè)中秋節(jié),老王本打算靜下來(lái)寫(xiě)寫(xiě)文章,但在無(wú)意間看到一部《麻雀》的諜戰(zhàn)片,使得老王兩眼冒金光,因?yàn)槔贤醭矚g...
    楚先生閱讀 379評(píng)論 0 1
  • 致孤單的你 每個(gè)人都會(huì)有孤單寂寞的時(shí)候,并不是有人陪伴就不會(huì)孤單寂寞,孤單的時(shí)候?qū)W會(huì)獨(dú)處,看一本書(shū),聽(tīng)一首歌,寫(xiě)一...
    猴爸陪你讀書(shū)閱讀 377評(píng)論 0 1

友情鏈接更多精彩內(nèi)容