Maison >développement back-end >tutoriel php >Explication détaillée du mécanisme de réflexion PHP
Cet article partage principalement avec vous une explication détaillée du mécanisme de réflexion PHP, notamment 1. Génération automatique de documents 2. Implémentation de l'architecture MVC 3. Implémentation des tests unitaires 4. Coopération avec les conteneurs DI pour résoudre les dépendances. .
1. Générer automatiquement des documents
Basé sur l'analyse réfléchie des classes, des interfaces, des structures internes des fonctions et des méthodes, des paramètres des méthodes et des fonctions, et des attributs et méthodes des classes, il peut être généré automatiquement Générer de la documentation.
<?phpclass Student{ const NORMAL = 1; const FORBIDDEN = 2; /** * 用户ID * @var 类型 */ public $id; /** * 获取id * @return int */ public function getId() { return $this->id; } public function setId($id = 1) { $this->id = $id; } }$ref = new ReflectionClass('Student');$doc = $ref->getDocComment();echo $ref->getName() . ':' . getComment($ref) , "<br/>";echo "属性列表:<br/>"; printf("%-15s%-10s%-40s<br/>", 'Name', 'Access', 'Comment');$attr = $ref->getProperties();foreach ($attr as $row) { printf("%-15s%-10s%-40s<br/>", $row->getName(), getAccess($row), getComment($row)); }echo "常量列表:<br/>"; printf("%-15s%-10s<br/>", 'Name', 'Value');$const = $ref->getConstants();foreach ($const as $key => $val) { printf("%-15s%-10s<br/>", $key, $val); }echo "<br/><br/>";echo "方法列表<br/>"; printf("%-15s%-10s%-30s%-40s<br/>", 'Name', 'Access', 'Params', 'Comment');$methods = $ref->getMethods();foreach ($methods as $row) { printf("%-15s%-10s%-30s%-40s<br/>", $row->getName(), getAccess($row), getParams($row), getComment($row)); }// 获取权限function getAccess($method){ if ($method->isPublic()) { return 'Public'; } if ($method->isProtected()) { return 'Protected'; } if ($method->isPrivate()) { return 'Private'; } }// 获取方法参数信息function getParams($method){ $str = ''; $parameters = $method->getParameters(); foreach ($parameters as $row) { $str .= $row->getName() . ','; if ($row->isDefaultValueAvailable()) { $str .= "Default: {$row->getDefaultValue()}"; } } return $str ? $str : ''; }// 获取注释function getComment($var){ $comment = $var->getDocComment(); // 简单的获取了第一行的信息,这里可以自行扩展 preg_match('/\* (.*) *?/', $comment, $res); return isset($res[1]) ? $res[1] : ''; }
Résultat de sortie :
Student: 属性列表: Name Access Comment id Public 用户ID 常量列表: Name Value NORMAL 1 FORBIDDEN 2 方法列表 Name Access Params Comment getId Public 获取id setId Public id,Default: 1
De nombreux frameworks ont désormais une architecture MVC, qui localise le contrôleur ($controller) en fonction du routage. information ) et le nom de la méthode ($method), puis utilisez la réflexion pour implémenter l'appel automatique.
$class = new ReflectionClass(ucfirst($controller) . 'Controller');$controller = $class->newInstance();if ($class->hasMethod($method)) { $method = $class->getMethod($method); $method->invokeArgs($controller, $arguments); } else { throw new Exception("{$controller} controller method {$method} not exists!"); }
Généralement, nous testerons les fonctions et les classes pour déterminer si elles peuvent renvoyer les résultats comme prévu. Nous pouvons utiliser la réflexion pour implémenter un test de classe simple et universel. cas.
<?phpclass Calc{ public function plus($a, $b) { return $a + $b; } public function minus($a, $b) { return $a - $b; } }function testEqual($method, $assert, $data){ $arr = explode('@', $method); $class = $arr[0]; $method = $arr[1]; $ref = new ReflectionClass($class); if ($ref->hasMethod($method)) { $method = $ref->getMethod($method); $res = $method->invokeArgs(new $class, $data); if($res === $assert){ echo "测试结果正确"; }; } } testEqual('Calc@plus', 3, [1, 2]);echo "<br/>"; testEqual('Calc@minus', -1, [1, 2]);
C'est la méthode de test de la classe. Vous pouvez également utiliser la réflexion pour implémenter la méthode de test de la fonction.
<?phpfunction title($title, $name){ return sprintf("%s. %s\r\n", $title, $name); }$function = new ReflectionFunction('title');echo $function->invokeArgs(array('Dr', 'Phil'));?>
Ceci est juste un cas de test que j'ai simplement écrit. Le framework de tests unitaires PHPUnit s'appuie fortement sur les fonctionnalités de Reflection, vous pouvez donc en apprendre davantage.
De nombreux frameworks tels que Laravel utilisent Reflection pour résoudre les problèmes d'injection de dépendances. Pour plus de détails, vous pouvez consulter le code source de Laravel pour analyse.
Ci-dessous, notre code implémente simplement un conteneur DI pour démontrer comment Reflection résout les problèmes d'injection de dépendances.
<?phpclass DI{ protected static $data = []; public function __set($k, $v) { self::$data[$k] = $v; } public function __get($k) { return $this->bulid(self::$data[$k]); } // 获取实例 public function bulid($className) { // 如果是匿名函数,直接执行,并返回结果 if ($className instanceof Closure) { return $className($this); } // 已经是实例化对象的话,直接返回 if(is_object($className)) { return $className; } // 如果是类的话,使用反射加载 $ref = new ReflectionClass($className); // 监测类是否可实例化 if (!$ref->isInstantiable()) { throw new Exception('class' . $className . ' not find'); } // 获取构造函数 $construtor = $ref->getConstructor(); // 无构造函数,直接实例化返回 if (is_null($construtor)) { return new $className; } // 获取构造函数参数 $params = $construtor->getParameters(); // 解析构造函数 $dependencies = $this->getDependecies($params); // 创建新实例 return $ref->newInstanceArgs($dependencies); } // 分析参数,如果参数中出现依赖类,递归实例化 public function getDependecies($params) { $data = []; foreach($params as $param) { $tmp = $param->getClass(); if (is_null($tmp)) { $data[] = $this->setDefault($param); } else { $data[] = $this->bulid($tmp->name); } } return $data; } // 设置默认值 public function setDefault($param) { if ($param->isDefaultValueAvailable()) { return $param->getDefaultValue(); } throw new Exception('no default value!'); } }class Demo{ public function __construct(Calc $calc) { echo $calc->plus(1, 2); } }class Calc{ public function plus($a, $b) { return $a + $b; } public function minus($a, $b) { return $a - $b; } }$di = new DI();$di->calc = 'Calc'; $di->demo = 'Demo';$di->demo;//输出结果为3
Recommandations associées :
Explication du mécanisme de réflexion php
Une brève explication des exemples de mécanismes de réflexion php et explication détaillée
Exemples de conception détaillés du plug-in d'implémentation du mécanisme de réflexion PHP
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!