Cómo usar la clase de reflexión de PHP y realizar la inyección de dependencia

La clase de reflexión extendida en PHP, la extensión se utiliza para analizar el programa PHP, exportar o extraer información detallada sobre clases, métodos, atributos, parámetros, etc., incluyendo comentarios.

class test{
    
    

    private $name;
    private $sex;
    function __construct(){
    
    
        $this->aaa='aaa';
    }
}

	$test=new test();

	$reflect=new ReflectionClass($test);
	$pro=$reflect->getDefaultProperties();
	print_r($pro); //打印结果:Array ( [name] => [sex] => )

	echo $test->aaa; //打印结果:aaa

En esta clase de prueba, dos variables miembro name y name yn a m e y sex, pero en el constructor, se declara una variable $ aaa, la clase se inicializa y la clase de reflexión se usa para imprimir los atributos de miembro predeterminados. Solo hay dos atributos de variable de miembro declarados, pero $ aaa todavía se puede encontrar la variable de la clase de impresión. Muestra el resultado.

== En su ejemplo, no es apropiado usar ReflectionClass, porque __construct solo se ejecutará cuando se instancia la clase. == En
otras palabras, ReflectionClass se trata más de la estructura de la declaración de la clase de reflexión, en lugar de la estructura después de que se instancia la clase, por lo que es correcto que no hay un atributo de salida aaa, porque el atributo aaa no existe (en el tiempo de declaración de clase).
Entonces, ¿cómo se ve el atributo aaa? La estructura después de la creación de instancias de reflexión debe usarse ReflectionObject, por ejemplo

<?php
class test{
    
    
    private $name;
    private $sex;
    function __construct(){
    
    
        $this->aaa='aaa';
    }
}
$test=new test();

$reflect=new ReflectionObject($test);
$pro=$reflect->getProperties();
print_r($pro);

Después de la instanciación, existirá el atributo aaa, y luego podrá ver el atributo aaa.
Debido a que PHP es un lenguaje "dinámico", las variables miembro de la clase se pueden declarar sin declaración, y también es posible declarar en la función.

Análisis sobre cómo realizar la inyección de dependencia a través de la reflexión de clases PHP

PHP tiene una API de reflexión completa, que brinda la capacidad de realizar ingeniería inversa de clases, interfaces, funciones, métodos y extensiones. A través de la capacidad que brinda el reflejo de la clase, podemos saber cómo se define la clase, qué atributos tiene, qué métodos, qué parámetros tiene el método y cuál es la ruta del archivo de la clase y otra información importante. También es oficialmente debido al reflejo de clases que muchos frameworks PHP pueden realizar la inyección de dependencias para resolver automáticamente las dependencias entre clases, lo que nos aporta mucha comodidad en nuestro desarrollo habitual. Este artículo explica principalmente cómo usar la reflexión de clases para lograr la inyección de dependencia (inyección de dependencia), y no describirá cada API en PHP Reflection una por una. Para obtener información detallada de referencia de API, consulte la documentación oficial.
Una vez más, la implementación de La inyección de dependencias es muy simple. Y no se puede aplicar al desarrollo real.
Para comprender mejor, veamos la reflexión de clases a través de un ejemplo y cómo implementar la inyección de dependencias.
La siguiente clase representa un punto en el sistema de coordenadas y tiene dos atributos: una abscisa x y una ordenada y.

/**
 * Class Point
 */
class Point
{
    
    
    public $x;
    public $y;

    /**
     * Point constructor.
     * @param int $x  horizontal value of point's coordinate
     * @param int $y  vertical value of point's coordinate
     */
    public function __construct($x = 0, $y = 0)
    {
    
    
        $this->x = $x;
        $this->y = $y;
    }
}

A continuación, esta clase representa un círculo, puede ver que hay un parámetro de la clase Point en su constructor, es decir, la clase Circle depende de la clase Point.

class Circle
{
    
    
    /**
     * @var int
     */
    public $radius;//半径

    /**
     * @var Point
     */
    public $center;//圆心点

    const PI = 3.14;

    public function __construct(Point $point, $radius = 1)
    {
    
    
        $this->center = $point;
        $this->radius = $radius;
    }
    
    //打印圆点的坐标
    public function printCenter()
    {
    
    
        printf('center coordinate is (%d, %d)', $this->center->x, $this->center->y);
    }

    //计算圆形的面积
    public function area()
    {
    
    
        return 3.14 * pow($this->radius, 2);
    }
}

ReflexiónClase

A continuación, usamos la reflexión para aplicar ingeniería inversa a la clase Circle.
Pase el nombre de la clase Circle a reflectClass para crear una instancia de un objeto de la clase ReflectionClass .

$reflectionClass = new reflectionClass(Circle::class);
//返回值如下
object(ReflectionClass)#1 (1) {
    
    
  ["name"]=>
  string(6) "Circle"
}
Refleja las constantes de la clase:
$reflectionClass->getConstants();
Devuelve una matriz asociativa de nombres y valores constantes:
array(1) {
    
    
  ["PI"]=>
  float(3.14)
}
Obtenga propiedades a través de la reflexión
$reflectionClass->getProperties();
Devuelve una matriz de objetos ReflectionProperty.
array(2) {
    
    
  [0]=>
  object(ReflectionProperty)#2 (2) {
    
    
    ["name"]=>
    string(6) "radius"
    ["class"]=>
    string(6) "Circle"
  }
  [1]=>
  object(ReflectionProperty)#3 (2) {
    
    
    ["name"]=>
    string(6) "center"
    ["class"]=>
    string(6) "Circle"
  }
}
Refleja los métodos definidos en la clase.
$reflectionClass->getMethods();

Devuelve una matriz de objetos ReflectionMethod

array(3) {
    
    
  [0]=>
  object(ReflectionMethod)#2 (2) {
    
    
    ["name"]=>
    string(11) "__construct"
    ["class"]=>
    string(6) "Circle"
  }
  [1]=>
  object(ReflectionMethod)#3 (2) {
    
    
    ["name"]=>
    string(11) "printCenter"
    ["class"]=>
    string(6) "Circle"
  }
  [2]=>
  object(ReflectionMethod)#4 (2) {
    
    
    ["name"]=>
    string(4) "area"
    ["class"]=>
    string(6) "Circle"
  }
}
También podemos obtener el constructor de la clase por separado a través de getConstructor (), y el valor de retorno es un objeto ReflectionMethod.
$constructor = $reflectionClass->getConstructor();
Refleja los parámetros del método
$parameters = $constructor->getParameters();

El valor de retorno es una matriz de objetos ReflectionParameter

array(2) {
    
    
  [0]=>
  object(ReflectionParameter)#3 (1) {
    
    
    ["name"]=>
    string(5) "point"
  }
  [1]=>
  object(ReflectionParameter)#4 (1) {
    
    
    ["name"]=>
    string(6) "radius"
  }
}

Inyección de dependencia

A continuación, escribimos una función llamada make, pasamos el nombre de la clase a la función make para devolver el objeto de la clase, en make, nos ayudará a inyectar las dependencias de la clase, es decir, en este ejemplo, nos ayudará a inyectar el Apunte el objeto al método de construcción de la clase Circle.

//构建类的对象
function make($className)
{
    
    
    $reflectionClass = new ReflectionClass($className);
    $constructor = $reflectionClass->getConstructor();
    $parameters  = $constructor->getParameters();
    $dependencies = getDependencies($parameters);
    
    return $reflectionClass->newInstanceArgs($dependencies);
}

//依赖解析
function getDependencies($parameters)
{
    
    
    $dependencies = [];
    foreach($parameters as $parameter) {
    
    
        $dependency = $parameter->getClass();
        if (is_null($dependency)) {
    
    
            if($parameter->isDefaultValueAvailable()) {
    
    
                $dependencies[] = $parameter->getDefaultValue();
            } else {
    
    
                //不是可选参数的为了简单直接赋值为字符串0
                //针对构造方法的必须参数这个情况
                //laravel是通过service provider注册closure到IocContainer,
                //在closure里可以通过return new Class($param1, $param2)来返回类的实例
                //然后在make时回调这个closure即可解析出对象
                //具体细节我会在另一篇文章里面描述
                $dependencies[] = '0';
            }
        } else {
    
    
            //递归解析出依赖类的对象
            $dependencies[] = make($parameter->getClass()->name);
        }
    }

    return $dependencies;
}

Después de definir el método make, lo usamos para ayudarnos a crear instancias de objetos de la clase Circle:

$circle = make('Circle');
$area = $circle->area();
/*var_dump($circle, $area);
object(Circle)#6 (2) {
  ["radius"]=>
  int(1)
  ["center"]=>
  object(Point)#11 (2) {
    ["x"]=>
    int(0)
    ["y"]=>
    int(0)
  }
}
float(3.14)*/

A través del ejemplo anterior, describí brevemente cómo usar el reflejo de las clases PHP para lograr la inyección de dependencia. La inyección de dependencia de Laravel también se logra a través de esta idea, pero el diseño es más preciso y usa una gran cantidad de devoluciones de llamada de cierre para lidiar con diversas complejidades Inyección de dependencias, consulte otro artículo sobre el contenedor de servicios de Laravel para obtener más detalles .

Supongo que te gusta

Origin blog.csdn.net/EasyTure/article/details/112603321
Recomendado
Clasificación