当前位置:首页 > CMS教程 > 其它CMS > 列表

Laravel框架源码解析之反射的使用详解

发布:smiling 来源: PHP粉丝网  添加日期:2022-03-06 11:40:22 浏览: 评论:0 

本文实例讲述了Laravel框架源码解析之反射的使用,分享给大家供大家参考,具体如下:

前言

PHP的反射类与实例化对象作用相反,实例化是调用封装类中的方法、成员,而反射类则是拆封类中的所有方法、成员变量,并包括私有方法等。就如“解刨”一样,我们可以调用任何关键字修饰的方法、成员。当然在正常业务中是建议不使用,比较反射类已经摒弃了封装的概念。

本章讲解反射类的使用及Laravel对反射的使用。

反射

反射类是PHP内部类,无需加载即可使用,你可以通过实例化 ReflectionClass 类去使用它。

方法

这里列举下PHP反射类常用的方法

方法名 注释

ReflectionClass::getConstant 获取定义过的一个常量

ReflectionClass::getConstants 获取一组常量

ReflectionClass::getConstructor 获取类的构造函数

ReflectionClass::getDefaultProperties 获取默认属性

ReflectionClass::getDocComment 获取文档注释

ReflectionClass::getEndLine 获取最后一行的行数

ReflectionClass::getFileName 获取定义类的文件名

ReflectionClass::getInterfaceNames 获取接口(interface)名称

ReflectionClass::getMethods 获取方法的数组

ReflectionClass::getModifiers 获取类的修饰符

ReflectionClass::getName 获取类名

ReflectionClass::getNamespaceName 获取命名空间的名称

ReflectionClass::getParentClass 获取父类

等等等等.... 所有关于类的方法、属性及其继承的父类、实现的接口都可以查询到。

详细文档请参考官网: http://php.net/manual/zh/class.reflectionclass.php

栗子

  1. <?php 
  2.  namespace A\B; 
  3.    
  4.  class Foo { } 
  5.    
  6.  $function = new \ReflectionClass('stdClass'); 
  7.    
  8.  var_dump($function->inNamespace()); 
  9.  var_dump($function->getName()); 
  10.  var_dump($function->getNamespaceName()); 
  11.  var_dump($function->getShortName()); 
  12.    
  13.  $function = new \ReflectionClass('A\\B\\Foo'); 
  14.    
  15.  var_dump($function->inNamespace()); 
  16.  var_dump($function->getName()); 
  17.  var_dump($function->getNamespaceName()); 
  18.  var_dump($function->getShortName()); 
  19. ?> 

输出结果

  1. bool(false) 
  2. string(8) "stdClass" 
  3. string(0) "" 
  4. string(8) "stdClass" 
  5.  
  6. bool(true) 
  7. string(7) "A\B\Foo" 
  8. string(3) "A\B" 
  9. string(3) "Foo" 

Laravel

Laravel在实现服务容器加载时使用了反射类,现在我们开启“解刨”模式

入口文件

index.php

  1. $app = require_once __DIR__.'/../bootstrap/app.php'
  2.  
  3. /* 
  4. |-------------------------------------------------------------------------- 
  5. | Run The Application 
  6. |-------------------------------------------------------------------------- 
  7. | 
  8. | Once we have the application, we can handle the incoming request 
  9. | through the kernel, and send the associated response back to 
  10. | the client's browser allowing them to enjoy the creative 
  11. | and wonderful application we have prepared for them. 
  12. | 
  13. */ 
  14.  
  15. $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 
  16.  
  17. $response = $kernel->handle( 
  18.  $request = Illuminate\Http\Request::capture() 
  19. ); 
  20.  
  21. $response->send(); 
  22.  
  23. $kernel->terminate($request$response); 

是引用语句发生的下一行调用了make方法,各位很清楚,make方法用于解析类,所有make方法的实现一定是在引用的文件内。

bootstrap\app.php

  1. $app = new Illuminate\Foundation\Application( 
  2.  realpath(__DIR__.'/../'
  3. ); 

laravel开始加载它的核心类,所有的实现从 Illuminate\Foundation\Application 开始。

Illuminate\Foundation\Application

  1. public function make($abstractarray $parameters = []) 
  2.   $abstract = $this->getAlias($abstract); 
  3.  
  4.   if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) { 
  5.    $this->loadDeferredProvider($abstract); 
  6.   } 
  7.  
  8.   return parent::make($abstract$parameters); 

在核心类中你可能准确的查找到make方法的存在,它加载了服务提供者随后调用了父类的方法make,要知道作为独立的模块 “服务容器”是绝对不能写在核心类的,懂点设计模式的都很清楚。

Illuminate\Container\Container

以 $api = $this->app->make('HelpSpot\API',['id'=>1]); 为例来讲解

  1. // 真正的make方法,它直接调用了resolve继续去实现make的功能 
  2. // $abstract = 'HelpSpot\API' 
  3. public function make($abstractarray $parameters = []) 
  4.  // $abstract = 'HelpSpot\API' 
  5.  return $this->resolve($abstract$parameters); 
  6.  
  7. ... 
  8.  
  9. protected function resolve($abstract$parameters = []) 
  10.  ... 
  11.  // 判断是否可以合理反射 
  12.  // $abstract = 'HelpSpot\API' 
  13.  if ($this->isBuildable($concrete$abstract)) { 
  14.   // 实例化具体实例 (实际并不是实例化,而是通过反射“解刨”了) 
  15.   $object = $this->build($concrete); 
  16.  } else { 
  17.   $object = $this->make($concrete); 
  18.  } 
  19.  ... 
  20.  
  21. public function build($concrete
  22.   // $concrete = 'HelpSpot\API' 
  23.   if ($concrete instanceof Closure) { 
  24.    return $concrete($this$this->getLastParameterOverride()); 
  25.   } 
  26.   // 实例化反射类 
  27.   $reflector = new ReflectionClass($concrete); 
  28.  
  29.   // 检查类是否可实例化 
  30.   if (! $reflector->isInstantiable()) { 
  31.    return $this->notInstantiable($concrete); 
  32.   } 
  33.  
  34.   $this->buildStack[] = $concrete
  35.  
  36.   // 获取类的构造函数 
  37.   $constructor = $reflector->getConstructor(); 
  38.     
  39.   if (is_null($constructor)) { 
  40.    array_pop($this->buildStack); 
  41.  
  42.    return new $concrete
  43.   } 
  44.  
  45.   $dependencies = $constructor->getParameters(); 
  46.  
  47.   $instances = $this->resolveDependencies( 
  48.    $dependencies 
  49.   ); 
  50.  
  51.   array_pop($this->buildStack); 
  52.      
  53.   // 从给出的参数创建一个新的类实例。 
  54.   return $reflector->newInstanceArgs($instances); 

可见一个服务容器就加载成功了。

Tags: Laravel源码解析 Laravel反射

分享到: