@a5635268
2016-01-15T13:25:34.000000Z
字数 7367
阅读 1894
PHP
PHP Reflection API是PHP5才有的新功能,它是用来导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。
class Reflection { }interface Reflector { }class ReflectionException extends Exception { }class ReflectionFunction implements Reflector { }class ReflectionParameter implements Reflector { }class ReflectionMethod extends ReflectionFunction { }class ReflectionClass implements Reflector { }class ReflectionObject extends ReflectionClass { }class ReflectionProperty implements Reflector { }class ReflectionExtension implements Reflector { }
用得比较多的就只有两个ReflectionClass与ReflectionObject,两个的用法都一样,只是前者针对类,后者针对对象,后者是继承前者的类;然后其中又有一些属性或方法能返回对应的Reflection对象(ReflectionProperty以及ReflectionMethod)
具体参考手册:http://php.net/manual/zh/class.reflectionclass.php
通过ReflectionClass,我们可以得到Person类的以下信息:
<?phpnamespace app;class Person{/*** For the sake of demonstration, we"re setting this private*/private $_allowDynamicAttributes = false;/** type=primary_autoincrement */protected $id = 0;/** type=varchar length=255 null */protected $name;/** type=text null */protected $biography;public function getId(){return $this->id;}public function setId($v){$this->id = $v;}public function getName(){return $this->name;}public function setName($v){$this->name = $v;}public function getBiography(){return $this->biography;}public function setBiography($v){$this->biography = $v;}}//传递类名进来$class = new \ReflectionClass('app\Person');//获取属性,不管该属性是否public$properties = $class->getProperties();foreach($properties as $property) {echo $property->getName()."\n";}// 输出:// _allowDynamicAttributes// id// name// biography//默认情况下,ReflectionClass会获取到所有的属性,private 和 protected的也可以。如果只想获取到private属性,就要额外传个参数:/** ReflectionProperty::IS_STATIC* ReflectionProperty::IS_PUBLIC* ReflectionProperty::IS_PROTECTED* ReflectionProperty::IS_PRIVATE*///↓↓ 注意一个|组合: 获得IS_PRIVATE或者IS_PROTECTED的属性$private_properties = $class->getProperties(\ReflectionProperty::IS_PRIVATE|\ReflectionProperty::IS_PROTECTED);foreach($private_properties as $property) {//↓↓如果该属性是受保护的属性;if($property->isProtected()) {// ↓↓ 获取注释$docblock = $property->getDocComment();preg_match('/ type\=([a-z_]*) /', $property->getDocComment(), $matches);echo $matches[1]."\n";}}// Output:// primary_autoincrement// varchar// text$data = array("id" => 1, "name" => "Chris", "biography" => "I am am a PHP developer");foreach($data as $key => $value) {if(!$class->hasProperty($key)) {throw new \Exception($key." is not a valid property");}if(!$class->hasMethod("get".ucfirst($key))) {throw new \Exception($key." is missing a getter");}if(!$class->hasMethod("set".ucfirst($key))) {throw new \Exception($key." is missing a setter");}$object = new Person();// http://php.net/manual/zh/class.reflectionmethod.php// getMethod 获得一个该方法的reflectionmethod对象,然后使用里面的invoke方法;$setter = $class->getMethod("set".ucfirst($key));$ok = $setter->invoke($object, $value);// Get the setter method and invoke it$getter = $class->getMethod("get".ucfirst($key));$objValue = $getter->invoke($object);// Now compareif($value == $objValue) {echo "Getter or Setter has modified the data.\n";} else {echo "Getter and Setter does not modify the data.\n";}}
ReflectionClass::getMethod — 获取一个类方法的 ReflectionMethod(这是个类报告了一个方法的有关信息)。
具体的参考:
<?phpclass HelloWorld {public function sayHelloTo($name) {return 'Hello ' . $name;}}$obj = new HelloWorld();// 第一个参数可以是对象,也可以是类$reflectionMethod = new ReflectionMethod($obj , 'sayHelloTo');/** public mixed ReflectionMethod::invoke ( object $object [, mixed $parameter [, mixed $... ]] )* 1. 获得某个类方法的ReflectionMethod* 2. $object 该方法所在的类实例的对象,然后第二参数起对号入座到该方法的每个参数;* 3. 通过invoke就可以执行这个方法了*/echo $reflectionMethod->invoke($obj, 'GangGe');
获得一个 ReflectionProperty 类实例 http://cn2.php.net/manual/zh/class.reflectionproperty.php
public mixed ReflectionProperty::getValue ([ object $object ] )
如果该获得该实例的类属性不是一个static的属性,就必须传该类的实例
<?phpclass Foo {public static $staticProperty = 'foobar';public $property = 'barfoo';protected $privateProperty = 'foofoo';}$reflectionClass = new ReflectionClass('Foo');var_dump($reflectionClass->getProperty('staticProperty')->getValue()); //静态属性可以不加参数var_dump($reflectionClass->getProperty('property')->getValue(new Foo)); //非静态属性必须加传一个类实例$reflectionProperty = $reflectionClass->getProperty('privateProperty'); //受保护的属性就要通过setAccessible设置其属性$reflectionProperty->setAccessible(true);var_dump($reflectionProperty->getValue(new Foo));?>
<?phpif (PHP_SAPI != 'cli') {exit('Please run it in terminal!');}if ($argc < 3) {exit('At least 2 arguments needed!');}$controller = ucfirst($argv[1]) . 'Controller';$action = 'action' . ucfirst($argv[2]);// 检查类是否存在if (!class_exists($controller)) {exit("Class $controller does not existed!");}// 获取类的反射$reflector = new ReflectionClass($controller);// 检查方法是否存在if (!$reflector->hasMethod($action)) {exit("Method $action does not existed!");}// 取类的构造函数,返回的是ReflectionMethod对象$constructor = $reflector->getConstructor();// 取构造函数的参数$parameters = $constructor->getParameters();// 遍历参数foreach ($parameters as $key => $parameter) {// 获取参数声明的类$injector = new ReflectionClass($parameter->getClass()->name);// 实例化参数声明类并填入参数列表$parameters[$key] = $injector->newInstance();}// 使用参数列表实例 controller 类$instance = $reflector->newInstanceArgs($parameters);// 执行$instance->$action();class HelloController{private $model;public function __construct(TestModel $model){$this->model = $model;}public function actionWorld(){echo $this->model->property, PHP_EOL;}}class TestModel{public $property = 'property';}
<?phpclass BlogAction {public function detail() {echo 'detail' . "\r\n";}public function test($year = 2014, $month = 4, $day = 21) {echo $year . '--' . $month . '--' . $day . "\r\n";}public function _before_detail() {echo __FUNCTION__ . "\r\n";}public function _after_detail() {echo __FUNCTION__ . "\r\n";}}// 执行detail方法$method = new ReflectionMethod('BlogAction', 'detail');$instance = new BlogAction();// 进行权限判断if ($method->isPublic()) {$class = new ReflectionClass('BlogAction');// 执行前置方法if ($class->hasMethod('_before_detail')) {$beforeMethod = $class->getMethod('_before_detail');if ($beforeMethod->isPublic()) {$beforeMethod->invoke($instance);}}$method->invoke(new BlogAction);// 执行后置方法if ($class->hasMethod('_after_detail')) {$beforeMethod = $class->getMethod('_after_detail');if ($beforeMethod->isPublic()) {$beforeMethod->invoke($instance);}}}// 执行带参数的方法$method = new ReflectionMethod('BlogAction', 'test');$params = $method->getParameters();foreach ($params as $param) {$paramName = $param->getName();if (isset($_REQUEST[$paramName])) {$args[] = $_REQUEST[$paramName];} elseif ($param->isDefaultValueAvailable()) {$args[] = $param->getDefaultValue();}}if (count($args) == $method->getNumberOfParameters()) {$method->invokeArgs($instance, $args);} else {echo 'parameters is wrong!';}
/*** 执行App控制器*/public function execApp() {// 创建action控制器实例$className = MODULE_NAME . 'Controller';$namespaceClassName = '\\apps\\' . APP_NAME . '\\controller\\' . $className;load_class($namespaceClassName, false);if (!class_exists($namespaceClassName)) {throw new \Exception('Oops! Module not found : ' . $namespaceClassName);}$controller = new $namespaceClassName();// 获取当前操作名$action = ACTION_NAME;// 执行当前操作//call_user_func(array(&$controller, $action)); // 其实吧,用这个函数足够啦!!!try {$methodInfo = new \ReflectionMethod($namespaceClassName, $action);if ($methodInfo->isPublic() && !$methodInfo->isStatic()) {$methodInfo->invoke($controller);} else { // 操作方法不是public类型,抛出异常throw new \ReflectionException();}} catch (\ReflectionException $e) {// 方法调用发生异常后,引导到__call方法处理$methodInfo = new \ReflectionMethod($namespaceClassName, '__call');$methodInfo->invokeArgs($controller, array($action, ''));}return;}