首頁 >後端開發 >php教程 >PHP的內省和反射

PHP的內省和反射

Jennifer Aniston
Jennifer Aniston原創
2025-02-27 08:35:13114瀏覽

Introspection and Reflection in PHP

核心要點

  • PHP 的內省機制允許程序員操作對像類並檢查類、接口、屬性和方法。這在設計時需要執行的類或方法未知時特別有用。
  • PHP 提供了各種內省函數,例如 class_exists()get_class()get_parent_class()is_subclass_of()。這些函數提供有關類的基本信息,例如它們的名稱、父類的名稱等等。
  • PHP 的反射 API 提供了類似於內省的功能,並且在提供用於完成反射任務的類和方法數量方面更為豐富。 ReflectionClass 類是 API 的主要類,用於對類、接口和方法應用反射。
  • PHP 中的內省和反射都是強大的工具,允許開發人員在運行時更好地了解其代碼,創建複雜的應用程序以及修改對象的運行時行為。但是,應謹慎使用它們,因為它們會使代碼更複雜且更難以理解。

PHP 內省機制是任何編程語言中的一種常見特性,它允許程序員操作對像類。當您在設計時不知道需要執行哪個類或方法時,您會發現內省特別有用。 PHP 中的內省提供了檢查類、接口、屬性和方法的有用功能。 PHP 提供大量可用於完成此任務的函數。為了幫助您理解內省,我將使用 PHP 中的示例簡要概述一些 PHP 的類、方法和函數,以突出它們的使用方式。在本文中,您將看到一些關於如何使用一些最有用的 PHP 內省函數的示例,以及一個專門介紹提供類似於內省功能的 API(反射 API)的部分。

PHP 內省函數

在第一個示例中,我將演示一些 PHP 的內省函數。您可以使用這些函數來提取有關類的基本信息,例如它們的名稱、父類的名稱等等。

  • class_exists() – 檢查是否已定義類
  • get_class() – 返回對象的類名
  • get_parent_class() – 返回對象的父類的類名
  • is_subclass_of() – 檢查對像是否具有給定的父類

以下是包含 IntrospectionChild 類定義的示例 PHP 代碼,以及上面列出的函數提取的信息輸出:

<code class="language-php"><?php
class Introspection {
    public function description() {
        echo "I am a super class for the Child class.\n";
    }
}

class Child extends Introspection {
    public function description() {
        echo "I'm " . get_class($this) , " class.\n";
        echo "I'm " . get_parent_class($this) , "'s child.\n";
    }
}

if (class_exists("Introspection")) {
    $introspection = new Introspection();
    echo "The class name is: " . get_class($introspection) . "\n";
    $introspection->description();
}

if (class_exists("Child")) {
    $child = new Child();
    $child->description();

    if (is_subclass_of($child, "Introspection")) {
        echo "Yes, " . get_class($child) . " is a subclass of Introspection.\n";
    } else {
        echo "No, " . get_class($child) . " is not a subclass of Introspection.\n";
    }
}
?></code>

上述代碼的輸出應如下所示:

<code class="language-php"><?php
class Introspection {
    public function description() {
        echo "I am a super class for the Child class.\n";
    }
}

class Child extends Introspection {
    public function description() {
        echo "I'm " . get_class($this) , " class.\n";
        echo "I'm " . get_parent_class($this) , "'s child.\n";
    }
}

if (class_exists("Introspection")) {
    $introspection = new Introspection();
    echo "The class name is: " . get_class($introspection) . "\n";
    $introspection->description();
}

if (class_exists("Child")) {
    $child = new Child();
    $child->description();

    if (is_subclass_of($child, "Introspection")) {
        echo "Yes, " . get_class($child) . " is a subclass of Introspection.\n";
    } else {
        echo "No, " . get_class($child) . " is not a subclass of Introspection.\n";
    }
}
?></code>

您可以使用 class_exists() 方法確定是否已定義給定的類,該方法採用表示要檢查的所需類的名稱的字符串參數,以及一個可選的布爾值,指示是否在過程中調用自動加載器。 get_class()get_parent_class() 方法分別返回對象的類名或其父類的類名。兩者都將對象實例作為參數。 is_subclass_of() 方法將對象實例作為其第一個參數,並將表示父類名的字符串作為第二個參數,並返回對像是否屬於作為參數給出的類的子類。

以下是一個第二個示例,其中包含 ICurrencyConverter 接口和 GBPCurrencyConverter 類的定義,以及上面列出的函數提取的信息輸出。與第一個示例一樣,我將首先列出函數,然後向您展示一些代碼。

  • get_declared_classes() – 返回所有已聲明類的列表
  • get_class_methods() – 返回類方法的名稱
  • get_class_vars() – 返回類的默認屬性
  • interface_exists() – 檢查接口是否已定義
  • method_exists() – 檢查對像是否定義了方法
<code>The class name is: Introspection
I am a super class for the Child class.
I'm Child class.
I'm Introspection's child.
Yes, Child is a subclass of Introspection.</code>

上述代碼的輸出應如下所示:

<code class="language-php"><?php
interface ICurrencyConverter {
    public function convert($currency, $amount);
}

class GBPCurrencyConverter implements ICurrencyConverter {
    public $name = "GBPCurrencyConverter";
    public $rates = array("USD" => 0.622846, "AUD" => 0.643478);
    protected $var1;
    private $var2;

    function __construct() {}

    function convert($currency, $amount) {
        return $this->rates[$currency] * $amount;
    }
}

if (interface_exists("ICurrencyConverter")) {
    echo "ICurrencyConverter interface exists.\n";
}

$classes = get_declared_classes();
echo "The following classes are available:\n";
print_r($classes);

if (in_array("GBPCurrencyConverter", $classes)) {
    print "GBPCurrencyConverter is declared.\n";

    $gbpConverter = new GBPCurrencyConverter();

    $methods = get_class_methods($gbpConverter);
    echo "The following methods are available:\n";
    print_r($methods);

    $vars = get_class_vars("GBPCurrencyConverter");
    echo "The following properties are available:\n";
    print_r($vars);

    echo "The method convert() exists for GBPCurrencyConverter: ";
    var_dump(method_exists($gbpConverter, "convert"));
}
?></code>

正如您可能已經猜到的那樣,interface_exists() 方法與第一個示例中討論的 class_exists() 方法非常相似。它確定是否已定義給定的接口,並採用接口名稱的字符串參數和可選的自動加載器布爾值。 get_declared_classes() 方法返回一個包含所有已定義類的名稱的數組,並且不帶任何參數。根據您加載的庫(編譯到 PHP 中或使用 require/include 加載),可能存在其他類。 get_class_method() 將對象實例或表示所需類的字符串作為參數,並返回由類定義的方法名稱數組。請注意,在 ICurrencyConverter 類中定義的所有屬性以及 get_class_vars() 方法返回的所有屬性中,只有 $name$rates 出現在輸出中。私有和受保護的屬性被跳過了。

PHP 反射 API

PHP 通過其反射 API 支持反射。正如您從 PHP 手冊中看到的那樣,反射 API 比內省機制要慷慨得多,並提供了大量的類和方法,您可以使用它們來完成反射任務。 ReflectionClass 類是 API 的主要類,用於對類、接口和方法應用反射,並提取有關所有類組件的信息。反射很容易在您的應用程序代碼中實現,並且與內省一樣,也非常直觀。以下是一個使用 ICurrencyConverter 接口和 ChildGBPCurrencyConverter 類相同定義來說明反射的示例:

<code class="language-php"><?php
class Introspection {
    public function description() {
        echo "I am a super class for the Child class.\n";
    }
}

class Child extends Introspection {
    public function description() {
        echo "I'm " . get_class($this) , " class.\n";
        echo "I'm " . get_parent_class($this) , "'s child.\n";
    }
}

if (class_exists("Introspection")) {
    $introspection = new Introspection();
    echo "The class name is: " . get_class($introspection) . "\n";
    $introspection->description();
}

if (class_exists("Child")) {
    $child = new Child();
    $child->description();

    if (is_subclass_of($child, "Introspection")) {
        echo "Yes, " . get_class($child) . " is a subclass of Introspection.\n";
    } else {
        echo "No, " . get_class($child) . " is not a subclass of Introspection.\n";
    }
}
?></code>

上述代碼的輸出應如下所示:

<code>The class name is: Introspection
I am a super class for the Child class.
I'm Child class.
I'm Introspection's child.
Yes, Child is a subclass of Introspection.</code>

getInterfaceNames() 方法返回一個包含類實現的接口名稱的數組。 getParentClass() 方法可以返回父類的 ReflectionClass 對象表示,如果不存在父類則返回 false。要列出 ReflectionClass 對象的名稱,您可以使用 getName() 方法,如上面的代碼所示。 getMethods() 方法檢索方法數組,並且可以將 ReflectionMethod::IS_STATICIS_PUBLICIS_PROTECTEDIS_PRIVATEIS_ABSTRACTIS_FINAL 的位掩碼組合作為可選參數,以根據可見性過濾列表。反射 API 提供了反射的良好實現,使您可以創建更複雜的應用程序,例如 ApiGen,但進一步討論超出了本文的目標。

總結

在本文中,您已經了解瞭如何使用 PHP 的內省函數和反射 API 來獲取有關類、接口、屬性和方法的信息。提取此信息的目的在於在運行時更好地了解您的代碼並創建複雜的應用程序。

(圖片來自 Fotolia)

(關於 PHP 中內省和反射的常見問題 (FAQ)) 此處省略了FAQ部分,因為篇幅過長,且與偽原創目標不符。 如有需要,可以單獨提出FAQ問題。

以上是PHP的內省和反射的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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