Maison  >  Article  >  développement back-end  >  Comment implémenter l'injection réfléchissante dans une interview PHP

Comment implémenter l'injection réfléchissante dans une interview PHP

王林
王林original
2019-09-29 17:48:142902parcourir

Comment implémenter l'injection réfléchissante dans une interview PHP

PHP dispose d'une API de réflexion complète, offrant la possibilité d'effectuer de l'ingénierie inverse sur des classes, des interfaces, des fonctions, des méthodes et des extensions. Grâce aux capacités fournies par la réflexion de classe, nous pouvons savoir comment la classe est définie, quels attributs elle possède, de quelles méthodes elle dispose, quels paramètres possède la méthode, quel est le chemin d'accès au fichier de classe et d'autres informations très importantes. C'est précisément grâce à la réflexion de classe que de nombreux frameworks PHP peuvent implémenter l'injection de dépendances pour résoudre automatiquement les dépendances entre les classes, ce qui apporte une grande commodité à notre développement quotidien.

Cet article explique principalement comment utiliser la réflexion de classe pour implémenter l'injection de dépendances (Dependency Injection). Il ne décrira pas chaque API de PHP Reflection une par une. Pour mieux comprendre, examinons la réflexion de classe à travers un exemple et comment implémenter l'injection de dépendances.

La classe suivante représente un point dans le système de coordonnées et possède deux attributs : abscisse x et ordonnée 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;
  }
}

La classe suivante représente un cercle. Vous pouvez voir qu'il y a un paramètre dans son constructeur qui est de la classe Point, c'est-à-dire que la classe Circle dépend de la classe 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);
  }
}

ReflectionClass

Ensuite, nous effectuons une ingénierie inverse de la classe Circle par réflexion. Passez le nom de la classe Circle à réflexionClass pour instancier un objet de la classe ReflectionClass.

$reflectionClass = new reflectionClass(Circle::class);
//返回值如下
object(ReflectionClass)#1 (1) {
 ["name"]=>
 string(6) "Circle"
}

Constantes réfléchies de la classe

$reflectionClass->getConstants();

Renvoie un tableau associatif de noms et de valeurs de constantes

array(1) {
 ["PI"]=>
 float(3.14)
}

Obtenir des propriétés par réflexion

$reflectionClass->getProperties();

Renvoyer un tableau composé d'objets 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"
 }
}

Refléter la méthode définie dans la classe

$reflectionClass->getMethods();

Renvoie un tableau d'objets 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"
 }
}

Nous pouvons également obtenir la méthode constructeur de la classe séparément via getConstructor(), Son la valeur de retour est un objet ReflectionMethod.

$constructor = $reflectionClass->getConstructor();

Refléter les paramètres de la méthode

$parameters = $constructor->getParameters();

La valeur de retour est un tableau composé d'objets ReflectionParameter.

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

Injection de dépendances

Bien, nous écrivons ensuite une fonction nommée make, passons le nom de la classe à la fonction make et renvoyons l'objet de la classe, dans make Ici, cela nous aidera à injecter les dépendances de la classe, c'est-à-dire que dans ce cas, cela nous aidera à injecter l'objet Point dans le constructeur de la classe 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;
}

Après avoir défini la méthode make, nous l'utilisons pour nous aider à instancier des objets de la classe 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)*/

À travers le ci-dessus Dans l'exemple, j'ai brièvement décrit comment utiliser la réflexion des classes PHP pour implémenter l'injection de dépendances. L'injection de dépendances de Laravel est également implémentée via cette idée, mais la conception est plus sophistiquée et utilise largement les rappels de fermeture pour gérer diverses dépendances complexes. injections.

Tutoriel recommandé : Tutoriel vidéo 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