PHP反射機(jī)制案例講解
簡(jiǎn)介
就算是類成員定義為private也可以在外部訪問(wèn),不用創(chuàng)建類的實(shí)例也可以訪問(wèn)類的成員和方法。
PHP自5.0版本以后添加了反射機(jī)制,它提供了一套強(qiáng)大的反射API,允許你在PHP運(yùn)行環(huán)境中,訪問(wèn)和使用類、方法、屬性、參數(shù)和注釋等,其功能十分強(qiáng)大,經(jīng)常用于高擴(kuò)展的PHP框架,自動(dòng)加載插件,自動(dòng)生成文檔,甚至可以用來(lái)擴(kuò)展PHP語(yǔ)言。由于它是PHP內(nèi)建的oop擴(kuò)展,為語(yǔ)言本身自帶的特性,所以不需要額外添加擴(kuò)展或者配置就可以使用。更多內(nèi)容見(jiàn)官方文檔。
反射類型
PHP反射API會(huì)基于類,方法,屬性,參數(shù)等維護(hù)相應(yīng)的反射類,已提供相應(yīng)的調(diào)用API。
| 類型 | 說(shuō)明 |
|---|---|
| Reflector | Reflector 是一個(gè)接口,被所有可導(dǎo)出的反射類所實(shí)現(xiàn)(implement) |
| Reflection | 反射(reflection)類 |
| ReflectionClass | 報(bào)告了一個(gè)類的有關(guān)信息 |
| ReflectionZendExtension | 報(bào)告Zend擴(kuò)展的相關(guān)信息 |
| ReflectionExtension | 報(bào)告了PHP擴(kuò)展的有關(guān)信息 |
| ReflectionFunction | 報(bào)告了一個(gè)函數(shù)的有關(guān)信息 |
| ReflectionFunctionAbstract | ReflectionFunction 的父類 |
| ReflectionMethod | 報(bào)告了一個(gè)方法的有關(guān)信息 |
| ReflectionObject | 報(bào)告了一個(gè)對(duì)象(object)的相關(guān)信息 |
| ReflectionParameter | 取回了函數(shù)或方法參數(shù)的相關(guān)信息 |
| ReflectionProperty | 報(bào)告了類的屬性的相關(guān)信息 |
訪問(wèn)
假設(shè)定義了一個(gè)類 User,我們首先需要建立這個(gè)類的反射類實(shí)例,然后基于這個(gè)實(shí)例可以訪問(wèn) User 中的屬性或者方法。不管類中定義的成員權(quán)限聲明是否為public,都可以獲取到。
<?php
namespace Extend;
use ReflectionClass;
use Exception;
/**
* 用戶相關(guān)類
* 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;
}
/**
* 設(shè)置用戶名
* @param string $username
*/
public function setUsername($username)
{
$this->username = $username;
}
/**
* 獲取密碼
* @return string
*/
private function getPassword()
{
return $this->password;
}
/**
* 設(shè)置密碼
* @param string $password
*/
private function setPassowrd($password)
{
$this->password = $password;
}
}
$class = new ReflectionClass('Extend\User'); // 將類名User作為參數(shù),即可建立User類的反射類
$properties = $class->getProperties(); // 獲取User類的所有屬性,返回ReflectionProperty的數(shù)組
$property = $class->getProperty('password'); // 獲取User類的password屬性ReflectionProperty
$methods = $class->getMethods(); // 獲取User類的所有方法,返回ReflectionMethod數(shù)組
$method = $class->getMethod('getUsername'); // 獲取User類的getUsername方法的ReflectionMethod
$constants = $class->getConstants(); // 獲取所有常量,返回常量定義數(shù)組
$constant = $class->getConstant('ROLE'); // 獲取ROLE常量
$namespace = $class->getNamespaceName(); // 獲取類的命名空間
$comment_class = $class->getDocComment(); // 獲取User類的注釋文檔,即定義在類之前的注釋
$comment_method = $class->getMethod('getUsername')->getDocComment(); // 獲取User類中g(shù)etUsername方法的注釋文檔
注意:創(chuàng)建反射類時(shí)傳送的類名,必須包含完整的命名空間,即使使用了 use 關(guān)鍵字。否則找不到類名會(huì)拋出異常。
交互
一旦創(chuàng)建了反射類的實(shí)例,我們不僅可以通過(guò)反射類訪問(wèn)原來(lái)類的方法和屬性,還能創(chuàng)建原來(lái)類的實(shí)例或則直接調(diào)用類里面的方法。
$class = new ReflectionClass('Extend\User'); // 將類名User作為參數(shù),即可建立User類的反射類
$instance = $class->newInstance('youyou', 1, '***'); // 創(chuàng)建User類的實(shí)例
$instance->setUsername('youyou_2'); // 調(diào)用User類的實(shí)例調(diào)用setUsername方法設(shè)置用戶名
$value = $instance->getUsername(); // 用過(guò)User類的實(shí)例調(diào)用getUsername方法獲取用戶名
echo $value;echo "\n"; // 輸出 youyou_2
$class->getProperty('username')->setValue($instance, 'youyou_3'); // 通過(guò)反射類ReflectionProperty設(shè)置指定實(shí)例的username屬性值
$value = $class->getProperty('username')->getValue($instance); // 通過(guò)反射類ReflectionProperty獲取username的屬性值
echo $value;echo "\n"; // 輸出 youyou_3
$class->getMethod('setUsername')->invoke($instance, 'youyou_4'); // 通過(guò)反射類ReflectionMethod調(diào)用指定實(shí)例的方法,并且傳送參數(shù)
$value = $class->getMethod('getUsername')->invoke($instance); // 通過(guò)反射類ReflectionMethod調(diào)用指定實(shí)例的方法
echo $value;echo "\n"; // 輸出 youyou_4
try {
$property = $class->getProperty('password_1');
$property->setAccessible(true); // 修改 $property 對(duì)象的可訪問(wèn)性
$property->setValue($instance, 'password_2'); // 可以執(zhí)行
$value = $property->getValue($instance); // 可以執(zhí)行
echo $value;echo "\n"; // 輸出 password_2
$class->getProperty('password')->setAccessible(true); // 修改臨時(shí)ReflectionProperty對(duì)象的可訪問(wèn)性
$class->getProperty('password')->setValue($instance, 'password');// 不能執(zhí)行,拋出不能訪問(wèn)異常
$value = $class->getProperty('password')->getValue($instance); // 不能執(zhí)行,拋出不能訪問(wèn)異常
$value = $instance->password; // 不能執(zhí)行,類本身的屬性沒(méi)有被修改,仍然是private
}catch(Exception $e){echo $e;}
注意事項(xiàng)
- 直接訪問(wèn) protected 或則 private 的熟悉或者方法會(huì)拋出異常
- 需要調(diào)用指定的 ReflectionProperty 或則 ReflectionMethod 對(duì)象 setAccessible(true)方法才能訪問(wèn)非公有成員
- 修改非公有成員的訪問(wèn)權(quán)限只作用于當(dāng)前的反射類的實(shí)例
- 需要注意獲取靜態(tài)成員和非靜態(tài)成員所使用的方法不一樣
- 獲取父類成員的方法和一般的不一樣
有時(shí)間會(huì)整理出反射類的API表,詳細(xì)的API列表可以先查閱官方文檔。
到此這篇關(guān)于PHP反射機(jī)制案例講解的文章就介紹到這了,更多相關(guān)PHP反射機(jī)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
php ajax數(shù)據(jù)傳輸和響應(yīng)方法
今天小編就為大家分享一篇php ajax數(shù)據(jù)傳輸和響應(yīng)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
php制作unicode解碼工具(unicode編碼轉(zhuǎn)換器)代碼分享
php制作Unicode編碼解碼在線轉(zhuǎn)換工具代碼分享2013-12-12
解決phpmyadmin中缺少mysqli擴(kuò)展問(wèn)題的方法
本篇文章是對(duì)解決phpmyadmin中缺少mysqli擴(kuò)展問(wèn)題的方法進(jìn)行了詳細(xì)的介紹。需要的朋友參考下2013-05-05
Laravel中創(chuàng)建Zip壓縮文件并提供下載
在Laravel中,創(chuàng)建Zip壓縮文件并提供下載是一個(gè)常見(jiàn)的需求,首先,我們需要確保服務(wù)器上安裝了Zip擴(kuò)展,然后使用ZipArchive類創(chuàng)建 Zip文件并添加需要壓縮的文件和目錄,最后提供直接下載或預(yù)覽后下載的方式供用戶下載,本文將介紹并提供詳細(xì)的步驟和代碼示例2024-03-03
php實(shí)現(xiàn)JWT(json web token)鑒權(quán)實(shí)例詳解
這篇文章主要介紹了php實(shí)現(xiàn)JWT(json web token)鑒權(quán)實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
laravel在中間件內(nèi)生成參數(shù)并且傳遞到控制器中的2種姿勢(shì)
今天小編就為大家分享一篇laravel在中間件內(nèi)生成參數(shù)并且傳遞到控制器中的2種姿勢(shì),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-10-10

