symfony 소스 코드 분석의 프레임 워 크 메 인 프로 세 스

10284 단어 symfonyphp
이것 은 symfony 3.3.0 버 전의 소스 코드 분석 을 바탕 으로 다음 과 같은 부분 을 포함한다.
프레임 메 인 프로 세 스
용기 생 성 및 사용
경로 생 성
  • 프로필 로드
  • 사건 위임
    소스 코드 를 분석 할 때 phopstrom 을 사용 하여 xdebug 확장 에 맞 춰 정지점 디 버 깅 을 하여 코드 분석 과 정리 에 큰 도움 이 되 었 습 니 다.
    1 호출 과정
    web/app.php
    $kernel = new AppKernel('prod', false);
    $response = $kernel->handle($request);

    Symfony\Component\HttpKernel\Kernel
    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
    {
        if (false === $this->booted) {
        	//          Bundle
            $this->boot();
        }
        //             Symfony\Component\HttpKernel\HttpKernel     handle   
        return $this->getHttpKernel()->handle($request, $type, $catch);
    }

    Symfony\Component\HttpKernel\HttpKernel
    private function handleRaw(Request $request, $type = self::MASTER_REQUEST)
    {
        $this->requestStack->push($request);
    
    //                
    $event = new GetResponseEvent($this, $request, $type);
    $this->dispatcher->dispatch(KernelEvents::REQUEST, $event);
    
    //                 
    if (false === $controller = $this->resolver->getController($request)) {
        throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". The route is wrongly configured.', $request->getPathInfo()));
    }
    //                          
    $event = new FilterControllerEvent($this, $controller, $request, $type);
    $this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event);
    $controller = $event->getController();
    
    //                                           
    $arguments = $this->argumentResolver->getArguments($request, $controller);
    
    //                          
    $event = new FilterControllerArgumentsEvent($this, $controller, $arguments, $request, $type);
    $this->dispatcher->dispatch(KernelEvents::CONTROLLER_ARGUMENTS, $event);
    $controller = $event->getController();
    $arguments = $event->getArguments();
    
    // call controller
    //       
    $response = call_user_func_array($controller, $arguments);
    
    if (!$response instanceof Response) {
    	//          Response    view     
    }
    
    return $this->filterResponse($response, $request, $type);
    }

    2 주류 프로 세 스 분석
    주류 프로 세 스 코드 를 간소화 하고 사건 위임 코드 를 무시 하 며 절 차 는 다음 과 같다.
    // 1.                
    $this->dispatcher->dispatch(KernelEvents::REQUEST, $event);
    // 2.                 
    $controller = $this->resolver->getController($request)
    // 3.                                           
    $arguments = $this->argumentResolver->getArguments($request, $controller);
    // 4.        
    $response = call_user_func_array($controller, $arguments);

    2.1 일치 경로 조회 에 필요 한 컨트롤 러
    여 기 는 이벤트 KernelEvents::REQUEST 를 촉발 합 니 다.이 이벤트 의 handler:Symfony\Component\\HttpKernel\\EventListener\RouterListener 는 경로,컨트롤 러 에 대한 분석 조 회 를 실 시 했 습 니 다.경로 가 생 성 되 지 않 으 면 경로 코드 를 생 성 할 수 있 습 니 다.
    # Symfony\Component\HttpKernel\EventListener\RouterListener
    public function onKernelRequest(GetResponseEvent $event)
    {
    	//               
        if ($request->attributes->has('_controller')) {
            return;
        }
    
        try {
            if ($this->matcher instanceof RequestMatcherInterface) {
            	//          
                $parameters = $this->matcher->matchRequest($request);
            } else {
                $parameters = $this->matcher->match($request->getPathInfo());
            }
            //                         request   attributes   
            // $parameters = [
            // 	'_controller' => "   ::  ",
            // 	'_route' =''
            // ]
            $request->attributes->add($parameters);
            unset($parameters['_route'], $parameters['_controller']);
            $request->attributes->set('_route_params', $parameters);
        } catch (ResourceNotFoundException $e) {
        	// ......
        } catch (MethodNotAllowedException $e) {
        	// ......
        }
    }

    경로 가 일치 하 는 코드 분석,프레임 워 크 는 경로 정 보 를 분석 하여 캐 시 파일 var/prod/apProd Project Container UrlMatcher.php 에 저장 합 니 다.구체 적 인 경로 생 성 코드 는 루트 코드 생 성 분석 구체 적 으로 살펴보다
    # Symfony\Bundle\FrameworkBundle\Routing\Router
    public function getRouteCollection()
    {
        if (null === $this->collection) {
        	//        routing.loader            load 
        	// Symfony\Bundle\FrameworkBundle\Routing\DelegatingLoader::load 
        	//    
        	//		$this->resource -> app/config/routing.yml 
        	//		$this->options['resource_type'] -> null 
            $this->collection = $this->container->get('routing.loader')->load($this->resource, $this->options['resource_type']);
            $this->resolveParameters($this->collection);
            $this->collection->addResource(new ContainerParametersResource($this->collectedParameters));
        }
    
        return $this->collection;
    }
    
    # Syfmony\Component\Routing\Router\Router
    public function matchRequest(Request $request)
    {
        $matcher = $this->getMatcher();
        if (!$matcher instanceof RequestMatcherInterface) {
            // fallback to the default UrlMatcherInterface
            return $matcher->match($request->getPathInfo());
        }
    
        return $matcher->matchRequest($request);
    }
    
    public function getMatcher()
    {
        // $this->getConfigCacheFactory() -> Symfony\Component\Config\ResourceCheckerConfigCacheFactory
        //             var/prod/appProdProjectContainerUrlMatcher.php
        $cache = $this->getConfigCacheFactory()->cache($this->options['cache_dir'].'/'.$this->options['matcher_cache_class'].'.php',
            //                     ,                    
            function (ConfigCacheInterface $cache) {
                // ......
            }
        );
    
        //                 var/cache/dev/app[ENV]DebugProjectContainerUrlMatcher.php
        require_once $cache->getPath();
        return $this->matcher = new $this->options['matcher_cache_class']($this->context);
    }

    2.2 컨트롤 러 의 인 스 턴 스 와 실행 할 방법 가 져 오기
    이 코드 의 호출 은 다음 과 같 습 니 다.
    Symfony\Bundle\FrameworkBundle\Controller\ControllerResolver extends 
    Symfony\Component\HttpKernel\Controller\ContainerControllerResolver extends 
    Symfony\Component\HttpKernel\Controller\ControllerResolver

    최종 실 행 된 핵심 코드 는 다음 과 같 습 니 다.
    # Symfony\Component\HttpKernel\Controller\ControllerResolver
    public function getController(Request $request)
    {
    	//       $controller    $request   attributes      ,            KernelEvents::CONTROLLER  handler RouterListener    
    	//                                   
        if (!$controller = $request->attributes->get('_controller')) {
            if (null !== $this->logger) {
                $this->logger->warning('Unable to look for the controller as the "_controller" parameter is missing.');
            }
    
            return false;
        }
    
        if (is_array($controller)) {
            return $controller;
        }
    
        if (is_object($controller)) {
            if (method_exists($controller, '__invoke')) {
                return $controller;
            }
    
            throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', get_class($controller), $request->getPathInfo()));
        }
    
        if (false === strpos($controller, ':')) {
            if (method_exists($controller, '__invoke')) {
                return $this->instantiateController($controller);
            } elseif (function_exists($controller)) {
                return $controller;
            }
        }
    
        $callable = $this->createController($controller);
    
        if (!is_callable($callable)) {
            throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($callable)));
        }
    
        return $callable;
    }

    이상 코드 의 핵심 세 션 은$controller=$request->attributes->get('controller')
    2.3 컨트롤 러 가 실행 할 방법 에 대해 반사 적 으로 방법 에 필요 한 인 자 를 얻 고 용 기 를 통 해 실례 화 된 대상 을 되 돌려 줍 니 다.
    컨트롤 러 방법 중의 매개 변수 처리 핵심 코드 는 다음 과 같다.
    # Symfony\Component\HttpKernel\Controller\ArgumentResolver
    public function getArguments(Request $request, $controller)
    {
        $arguments = array();
        //              ,          Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata
        foreach ($this->argumentMetadataFactory->createArgumentMetadata($controller) as $metadata) {
            // argument resolver           
            foreach ($this->argumentValueResolvers as $resolver) {
                if (!$resolver->supports($request, $metadata)) {
                    continue;
                }
    
                $resolved = $resolver->resolve($request, $metadata);
    
                if (!$resolved instanceof \Generator) {
                    throw new \InvalidArgumentException(sprintf('%s::resolve() must yield at least one value.', get_class($resolver)));
                }
                //$resolver      Generator yield
                foreach ($resolved as $append) {
                    $arguments[] = $append;
                }
    
                // continue to the next controller argument
                continue 2; //           
            }
    
            $representative = $controller;
    
            if (is_array($representative)) {
                $representative = sprintf('%s::%s()', get_class($representative[0]), $representative[1]);
            } elseif (is_object($representative)) {
                $representative = get_class($representative);
            }
    
            throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.', $representative, $metadata->getName()));
        }
    
        return $arguments;
    }
    
    public static function getDefaultArgumentValueResolvers()
    {
        return array(
            new RequestAttributeValueResolver(),
            new RequestValueResolver(),
            new SessionValueResolver(),
            new DefaultValueResolver(),
            new VariadicValueResolver(),
        );
    }

    좋은 웹페이지 즐겨찾기