php反射

weixin_30924079發表於2020-04-04

就算是類成員定義為private也可以在外部訪問,不用建立類的例項也可以訪問類的成員和方法。

PHP自5.0版本以後新增了反射機制,它提供了一套強大的反射API,允許你在PHP執行環境中,訪問和使用類、方法、屬性、引數和註釋等,其功能十分強大,經常用於高擴充套件的PHP框架,自動載入外掛,自動生成文件,甚至可以用來擴充套件PHP語言。由於它是PHP內建的oop擴充套件,為語言本身自帶的特性,所以不需要額外新增擴充套件或者配置就可以使用。

<?php 
namespace Extend;

use ReflectionClass;
use Exception;

/**
 * 使用者相關類
 * Class User
 * @package Extend
 */
class User{
    const ROLE = 'Students';
    public $username = '';
    private $password = '';

    public function __construct($username, $password)
    {
        $this->username = $username;
        $this->password = $password;
    }

    /**
     * 獲取使用者名稱
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * 設定使用者名稱
     * @param string $username
     */
    public function setUsername($username)
    {
        $this->username = $username;
    }

    /**
     * 獲取密碼
     * @return string
     */
    private function getPassword()
    {
        return $this->password;
    }

    /**
     * 設定密碼
     * @param string $password
     */
    private function setPassowrd($password)
    {
        $this->password = $password;
    }
}

$class = new ReflectionClass('Extend\User');  // 將類名User作為引數,即可建立User類的反射類
$properties = $class->getProperties();  // 獲取User類的所有屬性,返回ReflectionProperty的陣列
$property = $class->getProperty('password'); // 獲取User類的password屬性ReflectionProperty
$methods = $class->getMethods();   // 獲取User類的所有方法,返回ReflectionMethod陣列
$method = $class->getMethod('getUsername');  // 獲取User類的getUsername方法的ReflectionMethod
$constants = $class->getConstants();   // 獲取所有常量,返回常量定義陣列
$constant = $class->getConstant('ROLE');   // 獲取ROLE常量
$namespace = $class->getNamespaceName();  // 獲取類的名稱空間
$comment_class = $class->getDocComment();  // 獲取User類的註釋文件,即定義在類之前的註釋
$comment_method = $class->getMethod('getUsername')->getDocComment();  // 獲取User類中getUsername方法的註釋文件

注意:建立反射類時傳送的類名,必須包含完整的名稱空間,即使使用了 use 關鍵字。否則找不到類名會丟擲異常。

$class = new ReflectionClass('Extend\User');  // 將類名User作為引數,即可建立User類的反射類
$instance = $class->newInstance('youyou', 1, '***');  // 建立User類的例項

$instance->setUsername('youyou_2');  // 呼叫User類的例項呼叫setUsername方法設定使用者名稱
$value = $instance->getUsername();   // 用過User類的例項呼叫getUsername方法獲取使用者名稱
echo $value;echo "\n";   // 輸出 youyou_2

$class->getProperty('username')->setValue($instance, 'youyou_3');  // 通過反射類ReflectionProperty設定指定例項的username屬性值
$value = $class->getProperty('username')->getValue($instance);  // 通過反射類ReflectionProperty獲取username的屬性值
echo $value;echo "\n";   // 輸出 youyou_3

$class->getMethod('setUsername')->invoke($instance, 'youyou_4'); // 通過反射類ReflectionMethod呼叫指定例項的方法,並且傳送引數
$value = $class->getMethod('getUsername')->invoke($instance);    // 通過反射類ReflectionMethod呼叫指定例項的方法
echo $value;echo "\n";   // 輸出 youyou_4

try {
    $property = $class->getProperty('password_1');
    $property->setAccessible(true);   // 修改 $property 物件的可訪問性
    $property->setValue($instance, 'password_2');  // 可以執行
    $value = $property->getValue($instance);     // 可以執行
    echo $value;echo "\n";   // 輸出 password_2
    $class->getProperty('password')->setAccessible(true);    // 修改臨時ReflectionProperty物件的可訪問性
    $class->getProperty('password')->setValue($instance, 'password');// 不能執行,丟擲不能訪問異常
    $value = $class->getProperty('password')->getValue($instance);   // 不能執行,丟擲不能訪問異常
    $value = $instance->password;   // 不能執行,類本身的屬性沒有被修改,仍然是private
}catch(Exception $e){echo $e;}

注意事項

  1. 直接訪問 protected 或則 private 的熟悉或者方法會丟擲異常
  2. 需要呼叫指定的 ReflectionProperty 或則 ReflectionMethod 物件 setAccessible(true)方法才能訪問非公有成員
  3. 修改非公有成員的訪問許可權只作用於當前的反射類的例項
  4. 需要注意獲取靜態成員和非靜態成員所使用的方法不一樣
  5. 獲取父類成員的方法和一般的不一樣

轉載於:https://www.cnblogs.com/hanmengya/p/10944537.html

相關文章