最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 如何通过查源码的方式解决编程中遇到的问题?查源码定位问题的思路是什么?

    正文概述 转载于:掘金(王中阳Go)   2021-04-24   29

    首先抛出我的疑问:

    1. Laravel的底层是如何处理HTTP请求的?
    2. Laravel的Request是如何实现的?
    3. 为什么不需要配置Nginx的url解析,也不需要在Laravel的router中配置参数名称,却可以通过Request接收到参数呢?实现原理是什么?

    下面开始进入查源码之旅:

    1. 首先调研了一下Laravel的request是基于什么实现的?
    2. 知识点如下:Laravel的很多底层组件是基于Symfony实现的,比如:请求、响应、cookie、命令行,文件等。其中HttpFoundation组件是http请求中比较重要的基础组件,它可以独立于Symfony使用的,Laravel基于此做了进一步的封装,使用示例如下
    $request->input('param');
    $request->cookie('cookie');
    $request->file('file');
    
    1. 考虑到Laravel项目所有的HTTP请求都会转发到Laravel的入口文件(public/index.php),所以我们查看这个文件一探究竟:
    //创建Application实例,作为服务容器
    $app = new Illuminate\Foundation\Application(
        realpath(__DIR__.'/../')
    );
    
    //以单例方式在服务容器中将 App\Http\Kernel 实例绑定到 Illuminate\Contracts\Http\Kernel 接口
    $app->singleton(
        Illuminate\Contracts\Http\Kernel::class,
        App\Http\Kernel::class
    );
    
    //服务容器创建处理 HTTP 请求的内核实例(Kernel)
    $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
    
    //核心方法:处理 HTTP 请求的核心代码(核心代码会在下一部分展开来讲,先从上而下理清流程)
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
    
    //发送响应给发送请求的客户端
    $response->send();
    
    //内核实例终止程序,基于传入的request和response做一些收尾工作
    $kernel->terminate($request, $response);     
    
    1. 上面的注释已经比较清楚的解释了Laravel处理HTTP请求的内部实现流程。
    2. 我们再继续深入核心代码,研究一下“Laravel为什么在路由中无需指定参数是什么,在控制器方法中传入Request就可以获得参数了呢?”

    比如:

    //路由
    Route::resource('/index', 'IndexController');
    
    //controller中的方法
    function index(Request $request)
    {
          switch ($request->type) {
            .
            .
            .
        }
    }
    
    
    1. 下面的非核心代码用竖着的3个.省略,避免误导
    //laravel项目的入口文件 index.php
        .
        .
        .
            //重点1:handle()方法
    $response = $kernel->handle(
        $request = Illuminate\Http\Request::capture()
    );
        .
        .
        .
    
    
    //深入源码1 capture()
    public static function capture()
    {
        static::enableHttpMethodParameterOverride();
        //重点2:createFromBase() 方法
        return static::createFromBase(SymfonyRequest::createFromGlobals());
    }
    
    //我们再深入源码2 createFromBase()
    public static function createFromBase(SymfonyRequest $request)
    {
        if ($request instanceof static) {
            return $request;
        }
    
        $content = $request->content;
        
        //这是解决疑问的关键代码 duplicate 意为复制一份
        $request = (new static)->duplicate(
            $request->query->all(), $request->request->all(), $request->attributes->all(),
            $request->cookies->all(), $request->files->all(), $request->server->all()
        );
    
        $request->content = $content;
    
        $request->request = $request->getInputSource();
    
        return $request;
    }
    
    1. 发现了一个神奇的方法:duplicate(),意为复制一份。
    2. duplicate()方法的参数,包括request>query>all(),request->query->all(), request−>query−>all(),request->request->all()....等,即底层已经实现了所有query和request的接收,我们不需要单独声明也是可以接收到所有请求参数的。
    $request = (new static)->duplicate(
        $request->query->all(), $request->request->all(), $request->attributes->all(),
        $request->cookies->all(), $request->files->all(), $request->server->all()
    );
    
    1. 上面就是我查询源码的流程:

      1. 明确自己的问题(Request的底层实现)
      2. 明确自己排查问题的边界(从入口文件入手)
      3. 一层一层的深入查询源码(源码1->源码2-->源码3)
      4. 排除非核心代码,找到最核心代码(duplicate()方法)
    2. 下面是另外一位博主的思考总结,个人觉得总结的更系统和专业,Laravel底层如何处理HTTP请求,而我的总结更体现出我带着问题查看源码的思路、流程、反思、总结。

    3. 还有一个小插曲:

    源码这么写的原因是什么?不是重复操作吗? 如何通过查源码的方式解决编程中遇到的问题?查源码定位问题的思路是什么?

    1. 不认真呀,仔细看一下,2中的request是通过 (new static)->duplicate()克隆的新对象,和1中的request并不是相同的实例。

    文章结尾,放两个小题供大家消遣一下。

    1. 请设计一个函数,实现以下功能:将字符串"wang_zhong_yang"转换成"WangZhongYang";

    1.1 我的解题思路:

       public function actionCreate()
        {
            $str1 = "wang_zhong_yang";
            $arr1 = explode("_",$str1);
            foreach ($arr1 as $value){
                $str2 .=ucfirst($value);
            }
            var_dump($str2);
        }
    
    1. 请再设计一个函数,将字符串"wang_zhong_yang"转换成"wAngzHongyAng";

    2.2 我的解题思路:

        public function actionCreate()
        {
            $str1 = "wang_zhong_yang";
            $arr1 = explode("_",$str1);
            foreach ($arr1 as $value){
                //拆分
                $first = substr($value,0,1);
                $sec = substr($value,1,1);
                $sec = strtoupper($sec);
                $third = substr($value,2,strlen($value));
                $final = $first . $sec.$third;
                $str2 .= $final;
            }
            var_dump($str2);
        }
    

    我上面2道题的解法思路肯定不是最优解,欢迎大家不吝赐教。

    我们每次遇到不懂的知识点,是选择“马马虎虎会用就行”,还是选择“知其然,还知其所以然”,这2种选择在N年后给我们带来的结果是完全不同的。

    反思自己之前做项目一把solo代码,搬砖赶进度,不求甚解有些汗颜。

    在deadline之前,把需求搞定的同时,还是要尽可能多的搞清楚底层实现原理是什么。

    每日精进,如春起之苗,不见其长,日有所长。


    起源地 » 如何通过查源码的方式解决编程中遇到的问题?查源码定位问题的思路是什么?

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元