在 laravel 的 Controller 中可以见到
class DemoController {
public function test(Request $request) {}
}
laravel 帮我们自动把 $request 注入进来,是怎么办到的呢?
首先 test(Request $request)
这是类型提示(或类型约束)的标准PHP语法,换个写法就不觉的陌生了 test(int $number)
。
$request
为参数,Request
即为参数类型,那么通过获得参数 $request 的参数类型的类名 Request,就可以实例化了。
一共列举了 class
interface
abstract
int
(内置类型之一)self
parent
作为类型提示,以及两种没有类型提示的参数(有默认值和无默认值)。
目的:获得 Main
类的 abcd
方法的参数类型的类名。
class ClassParam {}
interface InterfaceParam {}
abstract class AbstractClassParam {}
class ParentClass {}
class Main extends ParentClass {
function abcd(
ClassParam $class_param,
InterfaceParam $interface_param,
AbstractClassParam $abstract_class_param,
int $int_param,
self $self_param,
parent $parent_param,
$has_default_param = 'default',
$no_default_param
) {
// ..
}
}
反射方法,返回 ReflectionMethod 对象
$method_reflecter = new ReflectionMethod(Main::class, 'abcd');
/**class ReflectionMethod#1 (2) {
public $name =>
string(4) "abcd"
public $class =>
string(4) "Main"
}*/
获取参数,返回 ReflectionParameter 对象数组
$parameters = $method_reflecter->getParameters();
/**array(8) {
[0] =>
class ReflectionParameter#2 (1) {
public $name =>
string(11) "class_param"
}
..
[7] =>
class ReflectionParameter#9 (1) {
public $name =>
string(16) "no_default_param"
}
}*/
获得参数类型
foreach ($parameters as $parameter) {
$type = $parameter->getType();
}
/**
class_param的类型是:
class ReflectionNamedType#10 (0) {
}
// 省略.. 除下面没有类型提示的参数类型为 NULL 外,皆是 ReflectionNamedType 对象
----
has_default_param的类型是:
NULL
----
no_default_param的类型是:
NULL
*/
排除没有类型提示的参数(类型为 NULL)
if (! $type instanceof ReflectionNamedType) {
// $has_default_param , $no_default_param
}
排除内置类型 int
string
等
if ($type->isBuiltin()) { //Builtin 翻译:内置
// int $int_param,
}
获得参数类型的名称
foreach ($parameters as $parameter) {
$type = $parameter->getType();
if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) {
continue;
}
$name = $type->getName();
}
/**ClassParam
InterfaceParam
AbstractClassParam
self
parent*/
上一步就已经获得了class
interface
abstract
三种类型的名称了,还有 self
parent
需要特殊处理,self
是当前类, parent
是父类。 laravel 用了 ReflectionParameter::getDeclaringClass
获得当前类。
//获取声明类,即参数声明所在的类
//返回 ReflectionClass 类反射对象
$class = $parameter->getDeclaringClass();
/**
class ReflectionClass#11 (1) {
public $name =>
string(4) "Main"
}
*/
$class->getName();
// Main
在这个例子中,所有参数声明所在的类都是 Main
,那么 self
就是 Main
, parent
就是 ParentClass
类。
以下就是 laravel (大于等于6版本) 的源码
public static function getParameterClassName($parameter)
{
// 这里 $has_default_param、$no_default_param 为 NULL,而其他都是 ReflectionNamedType 对象
$type = $parameter->getType();
// 排除 $has_default_param、$no_default_param、内置类型int等
if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) {
return;
}
//ClassParam、InterfaceParam、AbstractClassParam、self、parent
$name = $type->getName();
// getDeclaringClass 获取参数声明所在的类,函数(非类方法)则返回 null
// $class 为 ReflectionClass 类反射对象,
if (! is_null($class = $parameter->getDeclaringClass())) {
if ($name === 'self') {
return $class->getName(); // Main
}
// ReflectionClass::getParentClass 获取父类的反射对象
if ($name === 'parent' && $parent = $class->getParentClass()) {
return $parent->getName();
}
}
return $name;
}
注:在 laravel6 之前版本,获取参数类型相对简单,直接 $parameter->getClass()->name
(获取类型提示类名),但该方法已弃用。
$parameter->getClass()->name;
/**ClassParam
InterfaceParam
AbstractClassParam
Main
ParentClass*/
php.net
时而打不开,这个文档不错 https://www.w3cschool.cn/doc_php/php-class-reflection.html?lang=en