首頁  >  文章  >  後端開發  >  PHP中的反射是什麼?反射用法實例詳解

PHP中的反射是什麼?反射用法實例詳解

伊谢尔伦
伊谢尔伦原創
2017-07-01 10:33:481092瀏覽

物件導向編輯中物件被賦予了自省的能力,而這個自省的過程就是反射.

反射,直觀理解應時根據到達地找出出發地和來源.比方說,我給你一個光禿禿的物件,我可以僅僅透過這個物件就能知道它所屬的類別,擁有哪些方法.

反射指在PHP運行狀態中,擴展分析PHP程式,導出或提取出關於類別,方法,屬性,參數等詳細資訊,包括註解.這種動態取得資訊以及動態呼叫物件方法的功能稱為反射API

如何使用反射API

以下面程式碼為例

class HandsonBoy
{
    public $name = 'chenqionghe';
    public $age = 18;
    public function set($name,$value)
    {
        echo &#39;您正在设置私有属性&#39;.$name.&#39;<br >值为&#39;.$value.&#39;<br>&#39;;
        $this->$name = $value;
    }
    public function get($name)
    {
        if(!isset($this->$name))
        {
            echo &#39;未设置&#39;.$name;
            $this->$name = "正在为你设置默认值".&#39;<br>&#39;;
        }
        return $this->$name;
    }
}
$boy = new HandsonBoy();
echo $boy->name.&#39;<br />&#39;;
$boy->hair = &#39;short&#39;;

現在,要取得這個student物件的方法和屬性清單該怎麼做?可以用反射來實作,程式碼如下

$reflect = new ReflectionObject($boy);
$props = $reflect->getProperties();
//获取属性的名字
foreach($props as $prop)
{
    print $prop->getName().PHP_EOL;
}
//获取对象方法列表
$methos = $reflect->getMethods();
foreach($methos as $method)
{
    print $method->getName().PHP_EOL;
}

也可以不用反射API,使用class函數,傳回物件屬性的關聯陣列以及更多的資訊:(針對於公開的屬性和):

//返回对象属性的关联数组
var_dump(get_object_vars($boy));
//类属性
var_dump(get_class_vars(get_class($boy)));
//返回由类的属性的方法名组成的数组
var_dump(get_class_methods(get_class($boy)));

 反射API的功能顯然更強大,甚至能還原這個類別的原型,包括方法的存取權限,以下簡單封裝了一個列印類別的程式碼

/**
 * @param $classObject 对象或者类名
 */
function getClass($classObject)
{
    $object = new ReflectionClass($classObject);
    $className = $object->getName();
    $Methods = $Properties = array();
    foreach($object->getProperties() as $v)
    {
        $Properties[$v->getName()] = $v;
    }
    foreach($object->getMethods() as $v)
    {
        $Methods[$v->getName()] = $v;
    }
    echo "class {$className}\n{\n";
    is_array($Properties) && ksort($Properties);
    foreach($Properties as $k=>$v)
    {
        echo "\t";
        echo $v->isPublic() ? &#39;public&#39; : &#39;&#39;,$v->isPrivate() ? &#39;private&#39; :&#39;&#39;,$v->isProtected() ? &#39;protected&#39; : &#39;&#39;;
        $v->isStatic() ? &#39;static&#39; : &#39;&#39;;
        echo "\t{$k}\n";
    }
    echo "\n";
    if(is_array($Methods)) ksort($Methods);
    foreach($Methods as $k=>$v)
    {
        echo "\tfunction {$k}()\n";
    }
    echo "}\n";
}

 不僅如此,PHP手冊中關於反射API更是有幾十個,可以說,反射完整地描述了一個類別或物件的原型.反射不僅可以用於類別和物件,還可以用於函數,擴展模組,異常等.

##反射有什麼作用

反射可以用於文檔生成,因此可以用它對文件裡的類進行掃描,逐個生成描述文檔.

既然反射可以探知類內部結構, 那麼是不是可以用它做hook實現插件功能呢?或者是作動態代理呢?拋磚引玉,以下程式碼是個簡單的例子

<?php
class mysql
{
    function connect($db)
    {
        echo "连接到数据库{$db[0]}".PHP_EOL;
    }
}
class sqlproxy
{
    private $target;
    public function construct($tar)
    {
        $this->target[] = new $tar;
    }
    public function call($name,$args)
    {
        foreach($this->target as $obj)
        {
            $r = new ReflectionClass($obj);
            if($method = $r->getMethod($name))
            {
                if($method->isPublic() && !$method->isAbstract())
                {
                    echo "方法前拦截记录LOG".PHP_EOL;
                    $method->invoke($obj,$args);
                    echo "方法后拦截".PHP_EOL;
                }
            }
        }
    }
}
$obj = new sqlproxy(&#39;mysql&#39;);
$obj->connect(&#39;chenqionghe&#39;);

這裡真正操作類別是mysql類別,但是sqlproxy實現了根據動態傳入參數,代替實際的類別運行,並且在方法運行前後進行攔截,並且動態地改變類別中的方法和屬性.這就是簡單的動態代理.

在平常的開發中用到反射的地方並不多: 一個是對物件進行

調試,別一個是獲取類別的資訊.在MVC和插件開發中,使用反射很常見,但是反射的消耗也很大,在可以找到替代方案的情況下,就不要濫用.

PHP有Token函數,可以透過這個機制實現一些反射功能.從簡單靈活的角度講,使用已經提供的反射API是可取的.

很多時候,善用反射能保持程式碼的優雅和簡潔,但反射也會破壞類別的封裝性,因為反射可以使本不應該暴露的方法或屬性被強制暴露了出來,這既是優點也是缺點.

以上是PHP中的反射是什麼?反射用法實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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