PHP反射機(jī)制案例講解
簡介
就算是類成員定義為private也可以在外部訪問,不用創(chuàng)建類的實例也可以訪問類的成員和方法。
PHP自5.0版本以后添加了反射機(jī)制,它提供了一套強(qiáng)大的反射API,允許你在PHP運(yùn)行環(huán)境中,訪問和使用類、方法、屬性、參數(shù)和注釋等,其功能十分強(qiáng)大,經(jīng)常用于高擴(kuò)展的PHP框架,自動加載插件,自動生成文檔,甚至可以用來擴(kuò)展PHP語言。由于它是PHP內(nèi)建的oop擴(kuò)展,為語言本身自帶的特性,所以不需要額外添加擴(kuò)展或者配置就可以使用。更多內(nèi)容見官方文檔。
反射類型
PHP反射API會基于類,方法,屬性,參數(shù)等維護(hù)相應(yīng)的反射類,已提供相應(yīng)的調(diào)用API。
類型 | 說明 |
---|---|
Reflector | Reflector 是一個接口,被所有可導(dǎo)出的反射類所實現(xiàn)(implement) |
Reflection | 反射(reflection)類 |
ReflectionClass | 報告了一個類的有關(guān)信息 |
ReflectionZendExtension | 報告Zend擴(kuò)展的相關(guān)信息 |
ReflectionExtension | 報告了PHP擴(kuò)展的有關(guān)信息 |
ReflectionFunction | 報告了一個函數(shù)的有關(guān)信息 |
ReflectionFunctionAbstract | ReflectionFunction 的父類 |
ReflectionMethod | 報告了一個方法的有關(guān)信息 |
ReflectionObject | 報告了一個對象(object)的相關(guān)信息 |
ReflectionParameter | 取回了函數(shù)或方法參數(shù)的相關(guān)信息 |
ReflectionProperty | 報告了類的屬性的相關(guān)信息 |
訪問
假設(shè)定義了一個類 User,我們首先需要建立這個類的反射類實例,然后基于這個實例可以訪問 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)建反射類時傳送的類名,必須包含完整的命名空間,即使使用了 use 關(guān)鍵字。否則找不到類名會拋出異常。
交互
一旦創(chuàng)建了反射類的實例,我們不僅可以通過反射類訪問原來類的方法和屬性,還能創(chuàng)建原來類的實例或則直接調(diào)用類里面的方法。
$class = new ReflectionClass('Extend\User'); // 將類名User作為參數(shù),即可建立User類的反射類 $instance = $class->newInstance('youyou', 1, '***'); // 創(chuàng)建User類的實例 $instance->setUsername('youyou_2'); // 調(diào)用User類的實例調(diào)用setUsername方法設(shè)置用戶名 $value = $instance->getUsername(); // 用過User類的實例調(diào)用getUsername方法獲取用戶名 echo $value;echo "\n"; // 輸出 youyou_2 $class->getProperty('username')->setValue($instance, 'youyou_3'); // 通過反射類ReflectionProperty設(shè)置指定實例的username屬性值 $value = $class->getProperty('username')->getValue($instance); // 通過反射類ReflectionProperty獲取username的屬性值 echo $value;echo "\n"; // 輸出 youyou_3 $class->getMethod('setUsername')->invoke($instance, 'youyou_4'); // 通過反射類ReflectionMethod調(diào)用指定實例的方法,并且傳送參數(shù) $value = $class->getMethod('getUsername')->invoke($instance); // 通過反射類ReflectionMethod調(diào)用指定實例的方法 echo $value;echo "\n"; // 輸出 youyou_4 try { $property = $class->getProperty('password_1'); $property->setAccessible(true); // 修改 $property 對象的可訪問性 $property->setValue($instance, 'password_2'); // 可以執(zhí)行 $value = $property->getValue($instance); // 可以執(zhí)行 echo $value;echo "\n"; // 輸出 password_2 $class->getProperty('password')->setAccessible(true); // 修改臨時ReflectionProperty對象的可訪問性 $class->getProperty('password')->setValue($instance, 'password');// 不能執(zhí)行,拋出不能訪問異常 $value = $class->getProperty('password')->getValue($instance); // 不能執(zhí)行,拋出不能訪問異常 $value = $instance->password; // 不能執(zhí)行,類本身的屬性沒有被修改,仍然是private }catch(Exception $e){echo $e;}
注意事項
- 直接訪問 protected 或則 private 的熟悉或者方法會拋出異常
- 需要調(diào)用指定的 ReflectionProperty 或則 ReflectionMethod 對象 setAccessible(true)方法才能訪問非公有成員
- 修改非公有成員的訪問權(quán)限只作用于當(dāng)前的反射類的實例
- 需要注意獲取靜態(tài)成員和非靜態(tài)成員所使用的方法不一樣
- 獲取父類成員的方法和一般的不一樣
有時間會整理出反射類的API表,詳細(xì)的API列表可以先查閱官方文檔。
到此這篇關(guān)于PHP反射機(jī)制案例講解的文章就介紹到這了,更多相關(guān)PHP反射機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
php 模擬 asp.net webFrom 按鈕提交事件實例
需要php方面的項目開發(fā),php剛剛?cè)腴T,在寫按鈕提交過程中,asp.net里的按鈕事件更好些,下面有個實例,大家可以看看2014-10-10yii框架數(shù)據(jù)庫關(guān)聯(lián)查詢操作示例
這篇文章主要介紹了yii框架數(shù)據(jù)庫關(guān)聯(lián)查詢操作,結(jié)合實例形式總結(jié)分析了yii數(shù)據(jù)庫關(guān)聯(lián)查詢的常見操作方法與使用注意事項,需要的朋友可以參考下2019-10-10在Yii2中使用Pjax導(dǎo)致Yii2內(nèi)聯(lián)腳本載入失敗的原因分析
這篇文章主要介紹了在Yii2中使用Pjax導(dǎo)致Yii2內(nèi)聯(lián)腳本載入失敗的原因分析的相關(guān)資料,需要的朋友可以參考下2016-03-03