Laravel的验证器是怎么注入控制器的,求解释框架实现原理?

laravel中创建独立验证器

php artisan make:request StorePostRequest

/**
 * 存储新的博客文章。
 *
 * @param  \App\Http\Requests\StorePostRequest  $request
 * @return Illuminate\Http\Response
 */
public function store(StorePostRequest $request)
{
    // 传入的请求通过验证...

    // 获取通过验证的数据...
    $validated = $request->validated();

    // 获取部分通过验证的数据...
    $validated = $request->safe()->only(['name', 'email']);
    $validated = $request->safe()->except(['name', 'email']);
}

为什么这个$request可以随便变换类

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 7

反射获取方法的签名,从方法签名中提取参数类型,最后交由容器解析/生成对象,组装参数完毕后调用方法。

1周前

用了反射,递归找到所有依赖的类,并把包含的构造函数、普通方法等引用的类或者闭包进行实例化

1周前

以laravel8.x为例,简单来说就是反射解析再从ioc容器make实例化出来的 Illuminate\Routing\Route类中

   protected function runController()
    {
        return $this->controllerDispatcher()->dispatch(
            $this, $this->getController(), $this->getControllerMethod()
        );
    }

重点看dispatch

public function dispatch(Route $route, $controller, $method)
    {
       //解析参数  传入分别为路由传入的参数,控制器地址,函数名称
        $parameters = $this->resolveClassMethodDependencies(
            $route->parametersWithoutNulls(), $controller, $method
        );
       //存在默认的callAction函数运行callActoin
        if (method_exists($controller, 'callAction')) {
            return $controller->callAction($method, $parameters);
        }
     //运行对应的Controller
        return $controller->{$method}(...array_values($parameters));
    }

而后看解析函数

protected function resolveClassMethodDependencies(array $parameters, $instance, $method)
    {
        if (! method_exists($instance, $method)) {
            return $parameters;
        }
      //反射解析控制器跟函数所需参数 反射具体文档可以看看https://www.php.net/manual/zh/book.reflection.php
        return $this->resolveMethodDependencies(
            $parameters, new ReflectionMethod($instance, $method)
        );
    }
public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector)
    {
        $instanceCount = 0;

        $values = array_values($parameters);

        $skippableValue = new \stdClass;

       //反射解析参数一个个遍历处理
        foreach ($reflector->getParameters() as $key => $parameter) {
         //对路由参数跟控制器函数参数一一对比处理 ,request类就是从这里从ioc中make出来的
            $instance = $this->transformDependency($parameter, $parameters, $skippableValue);

            if ($instance !== $skippableValue) {
                $instanceCount++;
             //替换一下参数
                $this->spliceIntoParameters($parameters, $key, $instance);
            } elseif (! isset($values[$key - $instanceCount]) &&
                      $parameter->isDefaultValueAvailable()) {
                $this->spliceIntoParameters($parameters, $key, $parameter->getDefaultValue());
            }
        }

        return $parameters;
    }
1周前

给你一个最简单的样例(无配置文件),

如需连接 mysql,redis 需反射结合配置来自动完成类的创建


class foo{}

class Test
{
    protected foo $arg1;
    protected int $arg2;
    public function __construct(foo $arg1, int $arg2 = 123)
    {
        $this->arg1 = $arg1;
        $this->arg2 = $arg2;
    }

    public function run()
    {
        echo get_class($this->arg1) . PHP_EOL;
        echo __METHOD__ . '->' . __LINE__ . PHP_EOL;
    }
}


// 创建反射
$ref = new \ReflectionClass('Test');
// $ref = new \ReflectionClass(new Test('foo'));
// $ref = new \ReflectionClass(Test::class);


// 获取 __construct 的参数。
$params = $ref->getConstructor()->getParameters();

$arg1 = $params[0]->getType();
// var_dump($arg1->getName());
if (! $arg1->isBuiltin()) {
    $className = $arg1->getName();
    $param1 = new $className(); // 这里解析参数, 类似 StorePostRequest。laravel 比这个更为完善
} else{
    echo '标量无法自动创建'; //  $arg1 是数字,字符串就没法使用了,需要从配置获取数据,然后创建
    exit;
}

// var_dump($arg1);
// 创建实例
$obj = $ref->newInstance($param1); // $className 实例化用到的参数 $arg1, $arg2
// $obj = $ref->newInstanceArgs(['bar', 456]);
//$obj = $ref->newInstance(); // 无参数创建实例


echo $obj->run(); // Test::run->18
// var_dump($params); // 根据参数类型创建参数
1周前

file

實例化的時候 會通過resovle() 方法解析 然後後續會觸發這兩個回調 也是實際調用的地方

1周前

有两个问题,一个是 $request 如何注入进来的?首先StorePostRequest $request 就是类型提示写法,是标准 PHP 语法。利用类方法的反射就可以得到参数,StorePostRequest 属于参数的类型。能这么写,PHP 就肯定能拿到。实例化后传参给方法就是所谓的注入。第二个问题,StorePostRequest 和 Request 都能注入 $request,但可不是同一个 $request,因为不是一个类嘛。StorePostRequest 继承 Request,Request 的功能 StorePostRequest 都有,但 StorePostRequest 实例化的 $request 是个空壳,把 Request 实例化出来的 $request 身上所有的东东都搬到 StorePostRequest 实例化的 $request 身上,那不就一样了吗?所以 StorePostRequest 被实例化时干了一件事就是这个

1周前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!