手寫PHP API框架(三)之反射介紹

藏色散人
發布: 2023-04-11 10:32:02
轉載
4232 人瀏覽過

上一篇《手寫PHP API框架之Composer的安裝使用(二)》文章中我們介紹了Composer的安裝使用,這一文我們來介紹一下有關反射的概念介紹。

反射,直覺理解就是根據到達地找到出發地和來源。反射指在PHP運行狀態中,擴展分析PHP程序,導出或提出關於類別、方法、屬性、參數等的詳細信息,包括註釋。這種動態擷取資訊以及動態呼叫物件方法的功能稱為反射API。

不妨先來看一個demo:

<?php


function p($msg, $var)
{
    echo($msg.":".print_r($var, true)).PHP_EOL.PHP_EOL;
}


class Demo
{
    private $id;

    protected $name;

    public $skills = [];

    public function __construct($id, $name, $skills = [])
    {
        $this->id = $id;
        $this->name = $name;
        $this->skills = $skills;
    }

    public function getName()
    {
        return $this->name;
    }
    public function getSkill()
    {
        p(&#39;skill&#39;, $this->skills);
    }
}


$ref = new ReflectionClass(&#39;Demo&#39;);
if ($ref->isInstantiable()) {
    p(&#39;检查类是否可实例化isInstantiable&#39;, null);
}
$constructor = $ref->getConstructor();
p(&#39;获取构造函数getConstructor&#39;, $constructor);

$parameters = $constructor->getParameters();
foreach ($parameters as $param) {
    p(&#39;获取参数getParameters&#39;, $param);
}

if ($ref->hasProperty(&#39;name&#39;)) {
    $attr = $ref->getProperty(&#39;name&#39;);
    p(&#39;获取属性getProperty&#39;, $attr);
}

$attributes = $ref->getProperties();
foreach ($attributes as $row) {
    p(&#39;获取属性列表getProperties&#39;, $row->getName());
}

if ($ref->hasMethod(&#39;getSkill&#39;)) {
    $method = $ref->getMethod(&#39;getSkill&#39;);
    p(&#39;获取方法getMethod&#39;, $method);
}

$methods = $ref->getMethods();
foreach ($methods as $row) {
    p(&#39;获取方法列表getMethods&#39;, $row->getName());
}

$instance = $ref->newInstanceArgs([1, &#39;sai&#39;, [&#39;php&#39;, &#39;js&#39;]]);
p(&#39;newInstanceArgs&#39;, $instance);
登入後複製

輸出:

➜  php git:(main) php reflect.php 

检查类是否可实例化isInstantiable:

获取构造函数getConstructor:ReflectionMethod Object
(
    [name] => __construct
    [class] => Demo
)


获取参数getParameters:ReflectionParameter Object
(
    [name] => id
)


获取参数getParameters:ReflectionParameter Object
(
    [name] => name
)


获取参数getParameters:ReflectionParameter Object
(
    [name] => skills
)


获取属性getProperty:ReflectionProperty Object
(
    [name] => name
    [class] => Demo
)


获取属性列表getProperties:id

获取属性列表getProperties:name

获取属性列表getProperties:skills

获取方法getMethod:ReflectionMethod Object
(
    [name] => getSkill
    [class] => Demo
)


获取方法列表getMethods:__construct

获取方法列表getMethods:getName

获取方法列表getMethods:getSkill

newInstanceArgs:Demo Object
(
    [id:Demo:private] => 1
    [name:protected] => sai
    [skills] => Array
        (
            [0] => php
            [1] => js
        )

)
登入後複製

demo裡面就有使用了ReflectionClass類,當然ReflectionClass類別不只這些方法。

更多方法

ReflectionClass類別還有更多方法:

##ReflectionClass::getDocComment取得文件註解ReflectionClass::getEndLine 取得最後一行的行數ReflectionClass:: getExtension根據已定義的類別取得所在擴充功能的ReflectionExtension 物件ReflectionClass::getExtensionName取得定義的類別所在的擴充功能的名稱ReflectionClass::getFileName取得定義類別的檔案名稱ReflectionClass::getInterfaceNames#取得介面(interface)名稱ReflectionClass::getInterfaces使用介面ReflectionClass::getMethod #取得一個類別方法的ReflectionMethod。 ReflectionClass::getMethods取得方法的陣列ReflectionClass::getModifiers#取得類的修飾符ReflectionClass::getName取得類別名稱ReflectionClass::getNamespaceName#取得命名空間的名稱ReflectionClass::getParentClass#取得父類別ReflectionClass::getProperties取得一組屬性ReflectionClass::getProperty取得類別的一個屬性的ReflectionProperty##以取得起始行號取得靜態(static)屬性##取得靜態(static)屬性的值ReflectionClass::getTraitAliases傳回trait 別名的一個陣列ReflectionClass::getTraitNames#傳回這個類別所使用traits 的名稱的陣列ReflectionClass::getTraits傳回這個類別所使用的traits 陣列 #ReflectionClass::hasConstant檢查常數是否已經定義#ReflectionClass::hasMethod# #ReflectionClass::isInstance檢查類別的實例#ReflectionClass::isInstantiable檢查類別是否可實例化#ReflectionClass::isInterface檢查類別是否是一個介面(interface)ReflectionClass::isInternal檢查類別是否由擴充或核心在內部定義ReflectionClass::isIterableCheck whether this class is iterable#ReflectionClass::isIterateable 檢查是否可迭代(iterateable)ReflectionClass::isSubclassOf檢查是否為一個子類別#ReflectionClass::isTrait傳回了是否為一個trait#ReflectionClass::isUserDefined檢查是否由使用者定義的ReflectionClass::newInstance從指定的參數建立一個新的類別實例ReflectionClass::newInstanceArgs從給定的參數建立一個新的類別實例。 ReflectionClass::newInstanceWithoutConstructor#建立一個新的類別實例而不呼叫它的建構子ReflectionClass:: setStaticPropertyValue
方法 說明
#ReflectionClass::__construct 初始化ReflectionClass類別
ReflectionClass::export 匯出一個類別
ReflectionClass::getConstant 取得定義過的一個常數
ReflectionClass::getConstants #取得一組常數
ReflectionClass::getConstructor 取得類別的建構子
ReflectionClass::getDefaultProperties 取得預設屬性
##ReflectionClass:: getReflectionConstant Gets a ReflectionClassConstant for a class's constant
ReflectionClass::getReflectionConstants Gets class constants
ReflectionClass::getShortName 取得短名
#ReflectionClass::getStartLine
ReflectionClass::getStaticProperties
ReflectionClass::getStaticPropertyValue
##檢查方法是否已定義
#ReflectionClass::hasProperty 檢查屬性是否已定義
#ReflectionClass::implementsInterface 介面的實作
ReflectionClass::inNamespace 檢查是否位於命名空間中
ReflectionClass::isAbstract 檢查類別是否為抽象類別(abstract)
ReflectionClass::isAnonymous 檢查類別是否為匿名類別
ReflectionClass::isCloneable 傳回了一個類別是否可複製
ReflectionClass::isFinal 檢查類別是否宣告為final
###設定靜態屬性的值############ReflectionClass::__toString######傳回ReflectionClass 物件字串的表示形式。 ############

除去強大的ReflectionClass,還有Reflection、ReflectionClassConstant 、ReflectionMethod 、ReflectionFunctionAbstract等等。建議查看手冊:

#反射的實際應用

  • ##反射可以用於文件、文件產生。可以用它對文件裡的類別進行掃描,逐個生成描述文檔;

  • 既然反射可以探知類別的內部結構,那麼可以用它做hook實現插件功能;

  • 可以用來做動態代理,在未知或不確定類別名稱的情況下,動態產生和實例化一些類別和執行方法;

  • 依賴注入。對於多次繼承的類,我們可以透過多次反射來探索基類的結構,或是採用遞歸的形式反射,實現實例化所有繼承類,這也是PHP依賴注入的原理。

反射的優點

  • #支援反射的語言提供了一些在低階語言中難以實現的執行時間特性。

  • 可以在一定程度上避免硬編碼,提供靈活性和通用性。

  • 可以作為一個第一類物件來發現並修改原始碼的結構(如程式碼區塊、類別、方法、協定等)。

  • 可以在執行時期像對待原始程式碼語句一樣計算符號語法的字串(類似JavaScript的eval()函數),進而可將跟class或function相符的字串轉換成class或function的呼叫或引用。

  • 可以建立一個新的語言字節碼解釋器來給程式設計結構一個新的意義或用途。

反射的缺點

  • #學習成本高。反射導向的程式設計需要較多的高階知識,包括框架、關係映射和物件交互,以利用更通用的程式碼執行

  • 同樣因為反射的概念和語法都比較抽象,過度濫用反射技術會讓程式碼難以被其他人讀懂,不利於合作與交流

  • #反射在提高了程式碼彈性的同時,犧牲了一點點運作效率,有一定的消耗

  • 反射也會破壞類別的封裝性,把本不該暴露的方法或屬性暴露了出來

  • ##在平常的開發中,我們用到反射其實不多,為什麼要把它拿到這裡來說呢?一來是我們後面會使用到反射去實現Ioc容器,二來反射也是PHP核心功能之一,在我們流行的框架中十分常見,理解它是很有必要的。

這一節是比較獨立的,在後面的章節我們會使用它。

推薦學習:《

PHP影片教學

以上是手寫PHP API框架(三)之反射介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.im
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!