就算是類成員定義為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;}
注意事項
- 直接訪問 protected 或則 private 的熟悉或者方法會丟擲異常
- 需要呼叫指定的 ReflectionProperty 或則 ReflectionMethod 物件 setAccessible(true)方法才能訪問非公有成員
- 修改非公有成員的訪問許可權只作用於當前的反射類的例項
- 需要注意獲取靜態成員和非靜態成員所使用的方法不一樣
- 獲取父類成員的方法和一般的不一樣