Maison >développement back-end >tutoriel php >Explication détaillée du mécanisme de réflexion PHP

Explication détaillée du mécanisme de réflexion PHP

小云云
小云云original
2018-03-20 13:33:273375parcourir

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(&#39;Student&#39;);$doc = $ref->getDocComment();echo $ref->getName() . &#39;:&#39; . getComment($ref) , "<br/>";echo "属性列表:<br/>";
printf("%-15s%-10s%-40s<br/>", &#39;Name&#39;, &#39;Access&#39;, &#39;Comment&#39;);$attr = $ref->getProperties();foreach ($attr as $row) {
    printf("%-15s%-10s%-40s<br/>", $row->getName(), getAccess($row), getComment($row));
}echo "常量列表:<br/>";
printf("%-15s%-10s<br/>", &#39;Name&#39;, &#39;Value&#39;);$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/>", &#39;Name&#39;, &#39;Access&#39;, &#39;Params&#39;, &#39;Comment&#39;);$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 &#39;Public&#39;;
    }    if ($method->isProtected()) {        return &#39;Protected&#39;;
    }    if ($method->isPrivate()) {        return &#39;Private&#39;;
    }
}// 获取方法参数信息function getParams($method){
    $str = &#39;&#39;;    $parameters = $method->getParameters();    foreach ($parameters as $row) {        $str .= $row->getName() . &#39;,&#39;;        if ($row->isDefaultValueAvailable()) {            $str .= "Default: {$row->getDefaultValue()}";
        }
    }    return $str ? $str : &#39;&#39;;
}// 获取注释function getComment($var){
    $comment = $var->getDocComment();    // 简单的获取了第一行的信息,这里可以自行扩展
    preg_match(&#39;/\* (.*) *?/&#39;, $comment, $res);    return isset($res[1]) ? $res[1] : &#39;&#39;;
}

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

2. Implémenter l'architecture MVC

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) . &#39;Controller&#39;);$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!");
}

3. Implémenter les tests unitaires

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(&#39;@&#39;, $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(&#39;Calc@plus&#39;, 3, [1, 2]);echo  "<br/>";
testEqual(&#39;Calc@minus&#39;, -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(&#39;title&#39;);echo $function->invokeArgs(array(&#39;Dr&#39;, &#39;Phil&#39;));?>

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.

4. Coopérer avec le conteneur DI pour résoudre les dépendances

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(&#39;class&#39; . $className . &#39; not find&#39;);
        }        // 获取构造函数
        $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(&#39;no default value!&#39;);
    }
}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 = &#39;Calc&#39;;  
$di->demo = &#39;Demo&#39;;$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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn