Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung der Verwendung von Reflection in PHP

Detaillierte Erläuterung der Verwendung von Reflection in PHP

coldplay.xixi
coldplay.xixinach vorne
2020-06-16 17:46:292574Durchsuche

Detaillierte Erläuterung der Verwendung von Reflection in PHP

Lassen Sie uns über die Anwendung der Reflexion in der tatsächlichen Entwicklung sprechen.

  • Dokumente automatisch generieren
  • MVC-Architektur implementieren
  • Unit-Tests implementieren
  • Mit DI-Container arbeiten, um Abhängigkeiten aufzulösen

Dokumentation automatisch generieren

Dokumente können automatisch generiert werden, basierend auf der Reflexionsanalyse von Klassen, Schnittstellen, internen Strukturen von Funktionen und Methoden, Parametern von Methoden und Funktionen sowie Attributen und Methoden von Klassen.

/**
 * 学生类
 *
 * 描述信息
 */
class 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) , "\n";
echo "属性列表:\n";
printf("%-15s%-10s%-40s\n", 'Name', 'Access', 'Comment');
$attr = $ref->getProperties();
foreach ($attr as $row) {
    printf("%-15s%-10s%-40s\n", $row->getName(), getAccess($row), getComment($row));
}
echo "常量列表:\n";
printf("%-15s%-10s\n", 'Name', 'Value');
$const = $ref->getConstants();
foreach ($const as $key => $val) {
    printf("%-15s%-10s\n", $key, $val);
}
echo "\n\n";
echo "方法列表\n";
printf("%-15s%-10s%-30s%-40s\n", 'Name', 'Access', 'Params', 'Comment');
$methods = $ref->getMethods();
foreach ($methods as $row) {
    printf("%-15s%-10s%-30s%-40s\n", $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] : '';
}
​ ​ ​

Führen Sie php file.php aus, um die entsprechenden Dokumentinformationen anzuzeigen.

Implementierung der MVC-Architektur

Viele Frameworks verwenden jetzt die MVC-Architektur. Sie suchen die Namen von Controllern ($controller) und Methoden ($method) basierend auf Routing-Informationen und verwenden dann Reflektion um einen automatischen Anruf zu implementieren.

$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!");
}

Detaillierte Erläuterung der Verwendung von Reflection in PHP

Implementieren von Unit-Tests

Im Allgemeinen testen wir Funktionen und Klassen, um festzustellen, ob sie die von uns erwarteten Ergebnisse zurückgeben können Reflexion zur Implementierung eines einfachen und allgemeinen Klassentestfalls.

class 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);
        var_dump($res === $assert);
    }
}
testEqual('Calc@plus', 3, [1, 2]);
testEqual('Calc@minus', -1, [1, 2]);
​ ​ ​

Dies ist die Testmethode der Klasse, und Sie können Reflektion auch verwenden, um die Testmethode der Funktion zu implementieren.
Dies ist nur ein Testfall, den ich einfach geschrieben habe PHPUnit Das Unit-Testing-Framework basiert stark auf den Funktionen von Reflection, Sie können mehr darüber erfahren.

Funktioniert mit DI-Containern, um Abhängigkeiten aufzulösen

Laravel und viele andere Frameworks verwenden Reflection, um Abhängigkeitsinjektionsprobleme zu lösen. Weitere Informationen finden Sie im Laravel-Quellcode zur Analyse .
Unten implementiert unser Code einfach eine DI Containerdemonstration Reflection, um das Abhängigkeitsinjektionsproblem zu lösen.

class 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);
    }
}
$di = new DI();
$di->calc = 'Calc'; // 加载单元测试用例中 Calc 类
$di->demo = 'Demo';
$di->demo;

Beachten Sie die Reihenfolge von und calc oben, andernfalls wird ein Fehler gemeldet, da demo Abhängigkeit Demo zunächst definiert werden muss. Calc Bei der Instanziierung von
wird die Klasse Demo verwendet, was bedeutet, dass Calc von Demo abhängt. Wenn sie jedoch nicht in Calc gefunden wird, wird ein Fehler ausgegeben definieren                                                                     $data. $di->calc = 'Calc'

Reflexion ist eine sehr coole Funktion. Nutzen Sie sie, aber missbrauchen Sie sie nicht.

EndeBestehen Sie darauf, Originaltechnologie zu teilen. Ihre Unterstützung wird mich ermutigen, fortzufahren.

Empfohlenes Tutorial: „

PHP-Tutorial

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung der Verwendung von Reflection in PHP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.im. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen