찾다
PHP 프레임워크LaravelLaravel: 서비스 컨테이너 바인딩 및 구문 분석

다음은 laravel 튜토리얼 칼럼에 나온 Laravel: 서비스 컨테이너 바인딩 및 구문 분석에 대한 소개입니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다!

Laravel 실습: 서비스 컨테이너 바인딩 및 분석

머리말

 솔직히 사장님께서 라라벨 프레임워크 매뉴얼을 읽어보라고 하신 첫날 아침, 저는 정말 절실했습니다. 한번도 접해본 적이 없었기 때문입니다. , 쓰레기의 경우 laravel의 진입 임계 값이 실제로 약간 높지만 여전히 총알을 물고 읽어야합니다 (아직 많이 이해하지 못하고 아직 사용하지 않았지만).
회사 프로젝트의 코드를 기반으로 점차 Laravel에 익숙해졌지만 여전히 종속성 주입, ORM 작업, 사용자 인증 및 내 프로젝트의 비즈니스 로직과 관련된 기타 작업과 같은 일부 피상적인 기능에 머물었습니다. 일부 아키텍처는 서비스 제공자, 서비스 컨테이너, 미들웨어, Redis 등 처음부터 설정해야 하는 기본적인 것들을 실제로 운영한 적이 없어서(사장님이 이미 처음부터 해놓으셨기 때문에) 설명서를 읽을 때 여전히 약간 혼란 스럽습니다.
그래서 시간이 나면 포럼을 뒤지고 구글에서 Laravel의 핵심 아키텍처에 대한 소개와 사용법을 많이 찾아봅니다. (설명서를 읽은 후 읽어보면 이해하기 더 쉬울 것입니다.) 좋은 웹사이트에서 가르치는 것은 라라벨 핵심 아키텍처에 대한 학습을 ​​기록하는 것이라고 생각합니다.
웹사이트 주소: https://laraweb.net/ 이 웹사이트는 초보자에게 매우 적합한 내용이라고 생각합니다. 결국 일본어는 직접 번역하면 이해하기 쉽습니다.

서비스 컨테이너에 대하여

 설명서에는 다음과 같이 소개되어 있습니다. Laravel 서비스 컨테이너는 클래스 종속성을 관리하고 종속성 주입을 수행하는 데 사용되는 도구입니다. 종속성 주입이라는 멋진 용어는 본질적으로 클래스의 종속성이 생성자 또는 경우에 따라 "setter" 메서드를 통해 클래스에 "주입"된다는 것을 의미합니다. . . . . . (무슨 뜻인지 정말 모르겠습니다.)
  서비스 컨테이너는 클래스(서비스)의 인스턴스화를 관리하는 데 사용되는 메커니즘입니다. 서비스 컨테이너 사용법 바로보기

  1. 서비스 컨테이너에 클래스 등록(bind)

$this->app->bind('sender','MailSender');
//$this->app成为服务容器。

  2. 서비스 컨테이너에서 클래스 생성(make)

$sender = $this->app->make('sender');
//从服务容器($this->app)创建一个sender类。
在这种情况下,将返回MailSender的实例。

  서비스 컨테이너의 가장 간단한 사용법입니다. 다음은 서비스 컨테이너 상세 소개입니다
(주요 참고자료 : https://www.cnblogs.com/lyzg/...)

laravel 컨테이너의 기본 이해

  처음에는 index.php 파일이 Composer를 로딩합니다. 정의된 오토로더를 생성한 다음 bootstrap/app.php 스크립트에서 Laravel 애플리케이션의 인스턴스를 검색합니다. Laravel 자체에서 수행하는 첫 번째 작업은 애플리케이션/서비스 컨테이너의 인스턴스를 생성하는 것입니다.

$app = new Illuminate\Foundation\Application(
    dirname(__DIR__)
);

  이 파일은 요청이 laravel 프레임워크에 도달할 때마다 실행됩니다. 생성된 $app은 요청 수명 주기 전반에 걸쳐 고유한 laravel 프레임워크의 애플리케이션 인스턴스입니다. Laravel은 인증, 데이터베이스, 캐시, 메시지 큐 등을 포함한 많은 서비스를 제공합니다. $app는 컨테이너 관리 도구로서 거의 모든 서비스 구성 요소의 인스턴스화와 인스턴스의 수명주기 관리를 담당합니다. 특정 기능을 완료하기 위해 서비스 클래스가 필요한 경우 컨테이너를 통해 이 유형의 인스턴스만 확인하면 됩니다. 최종 사용 관점에서 볼 때 laravel 컨테이너에 의한 서비스 인스턴스 관리에는 주로 다음 측면이 포함됩니다.

  • 서비스 바인딩 및 구문 분석
  • 서비스 공급자 관리
  • 별칭의 역할
  • 종속성 주입

먼저 코드에서 컨테이너 인스턴스를 가져오는 방법을 이해하고 위의 네 가지 키를 알아보세요.

코드에서 컨테이너 인스턴스를 가져오는 방법

첫 번째는

$app = app();
//app这个辅助函数定义在\vendor\laravel\framework\src\Illuminate\Foundation\helper.php
里面,,这个文件定义了很多help函数,并且会通过composer自动加载到项目中。
所以,在参与http请求处理的任何代码位置都能够访问其中的函数,比如app()。

두 번째는

Route::get('/', function () {
    dd(App::basePath());
    return '';
});
//这个其实是用到Facade,中文直译貌似叫门面,在config/app.php中,
有一节数组aliases专门用来配置一些类型的别名,第一个就是'App' => Illuminate\Support\Facades\App::class,
具体的Google一下laravel有关门面的具体实现方式

입니다. 세 번째 옵션은 서비스 제공업체에서 $this->app을 직접 사용하는 것입니다. 서비스 제공자는 나중에 소개할 예정인데 지금은 소개한 뿐입니다. 서비스 제공자 클래스는 laravel 컨테이너에 의해 인스턴스화되기 때문에 이러한 클래스는 $app 인스턴스 속성을 정의하는 IlluminateSupportServiceProvider에서 상속됩니다.

abstract class ServiceProvider
{
    protected $app;

 laravel이 서비스 제공자를 인스턴스화할 때 이 $app 위에 laravel 컨테이너 인스턴스를 주입합니다. 따라서 서비스 제공자에서는 app() 함수나 App Facade를 사용하지 않고도 $this->$app을 통해 항상 laravel 컨테이너 인스턴스에 액세스할 수 있습니다.

서비스 바인딩 및 파싱 이해 방법

  간단히 말해서 컨테이너는 객체를 저장하는 용도이므로 객체 저장과 객체 제거 과정이 있어야 합니다. 이 객체를 저장하고 검색하는 과정을 Laravel에서는 서비스 바인딩 및 구문 분석이라고 합니다.

app()->bind('service', 'this is service1');

app()->bind('service2', [
    'hi' => function(){
        //say hi
    }
]);

class Service {

}

app()->bind('service3', function(){
    return new Service();
});

  바인딩의 특별한 경우인 싱글톤 바인딩 싱글톤도 있습니다(세 번째 매개변수는 true입니다). 컨테이너에 바인딩된 개체는 한 번만 구문 분석되며 후속 호출은 동일한 인스턴스를 반환합니다

public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}

  在绑定的时候,我们可以直接绑定已经初始化好的数据(基本类型、数组、对象实例),还可以用匿名函数来绑定。用匿名函数的好处在于,这个服务绑定到容器以后,并不会立即产生服务最终的对象,只有在这个服务解析的时候,匿名函数才会执行,此时才会产生这个服务对应的服务实例。
  实际上,当我们使用singleton,bind方法以及数组形式,(这三个方法是后面要介绍的绑定的方法),进行服务绑定的时候,如果绑定的服务形式,不是一个匿名函数,也会在laravel内部用一个匿名函数包装起来,这样的话, 不轮绑定什么内容,都能做到前面介绍的懒初始化的功能,这对于容器的性能是有好处的。这个可以从bind的源码中看到一些细节:

if (! $concrete instanceof Closure) {
    $concrete = $this->getClosure($abstract, $concrete);
}

看看bind的底层代码

public function bind($abstract, $concrete = null, $shared = false)

  第一个参数服务绑定名称,第二个参数服务绑定的结果(也就是闭包,得到实例),第三个参数就表示这个服务是否在多次解析的时候,始终返回第一次解析出的实例(也就是单例绑定singleton)。

  服务绑定还可以通过数组的方式:

app()['service'] = function(){
    return new Service();
};

绑定大概就这些,接下来看解析,也就是取出来用

$service= app()->make('service');

  这个方法接收两个参数,第一个是服务的绑定名称和服务绑定名称的别名,如果是别名,那么就会根据服务绑定名称的别名配置,找到最终的服务绑定名称,然后进行解析;第二个参数是一个数组,最终会传递给服务绑定产生的闭包。

看源码:

/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array  $parameters
 * @return mixed
 */
public function make($abstract, array $parameters = [])
{
    return $this->resolve($abstract, $parameters);
}

/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array  $parameters
 * @return mixed
 */
protected function resolve($abstract, $parameters = [])
{
    $abstract = $this->getAlias($abstract);

    $needsContextualBuild = ! empty($parameters) || ! is_null(
        $this->getContextualConcrete($abstract)
    );

    // If an instance of the type is currently being managed as a singleton we'll
    // just return an existing instance instead of instantiating new instances
    // so the developer can keep using the same objects instance every time.
    if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
        return $this->instances[$abstract];
    }

    $this->with[] = $parameters;

    $concrete = $this->getConcrete($abstract);

    // We're ready to instantiate an instance of the concrete type registered for
    // the binding. This will instantiate the types, as well as resolve any of
    // its "nested" dependencies recursively until all have gotten resolved.
    if ($this->isBuildable($concrete, $abstract)) {
        $object = $this->build($concrete);
    } else {
        $object = $this->make($concrete);
    }

    // If we defined any extenders for this type, we'll need to spin through them
    // and apply them to the object being built. This allows for the extension
    // of services, such as changing configuration or decorating the object.
    foreach ($this->getExtenders($abstract) as $extender) {
        $object = $extender($object, $this);
    }

    // If the requested type is registered as a singleton we'll want to cache off
    // the instances in "memory" so we can return it later without creating an
    // entirely new instance of an object on each subsequent request for it.
    if ($this->isShared($abstract) && ! $needsContextualBuild) {
        $this->instances[$abstract] = $object;
    }

    $this->fireResolvingCallbacks($abstract, $object);

    // Before returning, we will also set the resolved flag to "true" and pop off
    // the parameter overrides for this build. After those two things are done
    // we will be ready to return back the fully constructed class instance.
    $this->resolved[$abstract] = true;

    array_pop($this->with);

    return $object;
}

第一步:

$needsContextualBuild = ! empty($parameters) || ! is_null(
    $this->getContextualConcrete($abstract)
);

  该方法主要是区分,解析的对象是否有参数,如果有参数,还需要对参数做进一步的分析,因为传入的参数,也可能是依赖注入的,所以还需要对传入的参数进行解析;这个后面再分析。

第二步:

if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
    return $this->instances[$abstract];
}

  如果是绑定的单例,并且不需要上面的参数依赖。我们就可以直接返回 $this->instances[$abstract]。

第三步:

$concrete = $this->getConcrete($abstract);

...

/**
 * Get the concrete type for a given abstract.
 *
 * @param  string  $abstract
 * @return mixed   $concrete
 */
protected function getConcrete($abstract)
{
    if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
        return $concrete;
    }

    // If we don't have a registered resolver or concrete for the type, we'll just
    // assume each type is a concrete name and will attempt to resolve it as is
    // since the container should be able to resolve concretes automatically.
    if (isset($this->bindings[$abstract])) {
        return $this->bindings[$abstract]['concrete'];
    }

    return $abstract;
}

  这一步主要是先从绑定的上下文找,是不是可以找到绑定类;如果没有,则再从 $bindings[] 中找关联的实现类;最后还没有找到的话,就直接返回 $abstract 本身。

// We're ready to instantiate an instance of the concrete type registered for
// the binding. This will instantiate the types, as well as resolve any of
// its "nested" dependencies recursively until all have gotten resolved.
if ($this->isBuildable($concrete, $abstract)) {
    $object = $this->build($concrete);
} else {
    $object = $this->make($concrete);
}

...

/**
 * Determine if the given concrete is buildable.
 *
 * @param  mixed   $concrete
 * @param  string  $abstract
 * @return bool
 */
protected function isBuildable($concrete, $abstract)
{
    return $concrete === $abstract || $concrete instanceof Closure;
}

  如果之前找到的 $concrete 返回的是 $abstract 值,或者 $concrete 是个闭包,则执行 $this->build($concrete),否则,表示存在嵌套依赖的情况,则采用递归的方法执行 $this->make($concrete),直到所有的都解析完为止。

$this->build($concrete)

/**
 * Instantiate a concrete instance of the given type.
 *
 * @param  string  $concrete
 * @return mixed
 *
 * @throws \Illuminate\Contracts\Container\BindingResolutionException
 */
public function build($concrete)
{
    // If the concrete type is actually a Closure, we will just execute it and
    // hand back the results of the functions, which allows functions to be
    // used as resolvers for more fine-tuned resolution of these objects.
    // 如果传入的是闭包,则直接执行闭包函数,返回结果
    if ($concrete instanceof Closure) {
        return $concrete($this, $this->getLastParameterOverride());
    }

    // 利用反射机制,解析该类。
    $reflector = new ReflectionClass($concrete);

    // If the type is not instantiable, the developer is attempting to resolve
    // an abstract type such as an Interface of Abstract Class and there is
    // no binding registered for the abstractions so we need to bail out.
    if (! $reflector->isInstantiable()) {
        return $this->notInstantiable($concrete);
    }

    $this->buildStack[] = $concrete;

    // 获取构造函数
    $constructor = $reflector->getConstructor();

    // If there are no constructors, that means there are no dependencies then
    // we can just resolve the instances of the objects right away, without
    // resolving any other types or dependencies out of these containers.
    // 如果没有构造函数,则表明没有传入参数,也就意味着不需要做对应的上下文依赖解析。
    if (is_null($constructor)) {
        // 将 build 过程的内容 pop,然后直接构造对象输出。
        array_pop($this->buildStack);

        return new $concrete;
    }

    // 获取构造函数的参数
    $dependencies = $constructor->getParameters();

    // Once we have all the constructor's parameters we can create each of the
    // dependency instances and then use the reflection instances to make a
    // new instance of this class, injecting the created dependencies in.
    // 解析出所有上下文依赖对象,带入函数,构造对象输出
    $instances = $this->resolveDependencies(
        $dependencies
    );

    array_pop($this->buildStack);

    return $reflector->newInstanceArgs($instances);
}

上面这一段有关解析make的介绍主要参考:
coding01:看 Laravel 源代码了解 Container

  这一篇就主要学习laravel的服务容器以及它的绑定和解析,虽然目前能力无法对框架源码每一个地方都弄懂,但通过这几篇优秀的文章,我将其进行整理结合,这过程让我更加理解laravel的一些核心内容,起码别人问起来我多多少少能说出一些,这就是进步。

  后面有关服务提供者,依赖注入,中间件等内容的学习将放在后续的博客文章中,欢迎看看我的其他博客文章:https://zgxxx.github.io/。
  以上相关知识的引用已经注明出处,若有侵权,请联系我,感谢这些优秀文章的作者

위 내용은 Laravel: 서비스 컨테이너 바인딩 및 구문 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 segmentfault에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
Laravel의 다양성 : 간단한 사이트에서 복잡한 시스템에 이르기까지Laravel의 다양성 : 간단한 사이트에서 복잡한 시스템에 이르기까지Apr 13, 2025 am 12:13 AM

Laravel Development Project는 다양한 크기와 복잡성의 요구에 맞게 유연성과 힘으로 인해 선정되었습니다. Laravel은 간단한 블로그에서 복잡한 엔터프라이즈 수준 시스템에 이르기까지 라우팅 시스템, Eloquentorm, Artisan Command Line 및 기타 기능을 제공합니다.

Laravel (PHP) vs. Python : 개발 환경 및 생태계Laravel (PHP) vs. Python : 개발 환경 및 생태계Apr 12, 2025 am 12:10 AM

개발 환경과 생태계에서 Laravel과 Python의 비교는 다음과 같습니다. 1. Laravel의 개발 환경은 간단하며 PHP와 작곡가 만 필요합니다. Laravelforge와 같은 풍부한 확장 패키지를 제공하지만 확장 패키지 유지 보수는시기 적절하지 않을 수 있습니다. 2. 파이썬의 개발 환경도 간단하며 파이썬과 PIP 만 필요합니다. 생태계는 거대하고 여러 분야를 다루지 만 버전 및 종속성 관리는 복잡 할 수 있습니다.

Laravel 및 백엔드 : 파워링 웹 응용 프로그램 논리Laravel 및 백엔드 : 파워링 웹 응용 프로그램 논리Apr 11, 2025 am 11:29 AM

Laravel은 백엔드 논리에서 어떻게 중요한 역할을합니까? 라우팅 시스템, eloquentorm, 인증 및 승인, 이벤트 및 청취자, 성능 최적화를 통해 백엔드 개발을 단순화하고 향상시킵니다. 1. 라우팅 시스템은 URL 구조의 정의 및 요청 처리 로직을 정의 할 수 있습니다. 2. eloquentorm은 데이터베이스 상호 작용을 단순화합니다. 3. 인증 및 인증 시스템은 사용자 관리에 편리합니다. 4. 이벤트와 리스너는 느슨하게 결합 된 코드 구조를 구현합니다. 5. 성능 최적화는 캐싱 및 대기열을 통한 응용 프로그램 효율성을 향상시킵니다.

Laravel이 왜 그렇게 인기가 있습니까?Laravel이 왜 그렇게 인기가 있습니까?Apr 02, 2025 pm 02:16 PM

Laravel의 인기에는 단순화 된 개발 프로세스, 쾌적한 개발 환경 및 풍부한 기능이 포함됩니다. 1) PHP의 유연성을 결합하여 Rubyonrails의 설계 철학을 흡수합니다. 2) 개발 효율성을 향상시키기 위해 Eloquentorm, Blade Template Engine 등과 같은 도구를 제공하십시오. 3) MVC 아키텍처 및 종속성 주입 메커니즘은 코드를보다 모듈화적이고 테스트 가능하게 만듭니다. 4) 캐싱 시스템 및 모범 사례와 같은 강력한 디버깅 도구 및 성능 최적화 방법을 제공합니다.

어느 것이 더 낫습니까, 장고 또는 라벨?어느 것이 더 낫습니까, 장고 또는 라벨?Mar 28, 2025 am 10:41 AM

Django와 Laravel은 모두 풀 스택 프레임 워크입니다. Django는 Python 개발자 및 복잡한 비즈니스 논리에 적합한 반면 Laravel은 PHP 개발자 및 우아한 구문에 적합합니다. 1. Django는 파이썬을 기반으로하며 빠른 개발 및 높은 동시성에 적합한 "배터리 완성"철학을 따릅니다. 2. Laravel은 PHP를 기반으로하며 개발자 경험을 강조하며 중소형 프로젝트에 적합합니다.

더 나은 PHP 또는 Laravel은 무엇입니까?더 나은 PHP 또는 Laravel은 무엇입니까?Mar 27, 2025 pm 05:31 PM

Laravel은 PHP 기반 프레임 워크이기 때문에 PHP와 Laravel은 직접 비교할 수 없습니다. 1.PHP는 소규모 프로젝트 또는 빠른 프로토 타이핑에 적합하고 간단하고 직접적이기 때문에 적합합니다. 2. Laravel은 대규모 프로젝트 또는 효율적인 개발에 적합하지만 풍부한 기능과 도구를 제공하지만 가파른 학습 곡선을 가지고 있으며 순수한 PHP만큼 좋지 않을 수 있습니다.

Laravel은 프론트 엔드 또는 백엔드입니까?Laravel은 프론트 엔드 또는 백엔드입니까?Mar 27, 2025 pm 05:31 PM

laravelisabackendframeworkbuiltonphp, 디자인 된 forwebapplicationdevelopment.itfocusesonserver-sidelogic, databasemanagement, andapplicationtructure, and canbeintegratedwithfrontendechnologies likevue.jsorreactforfull-stackdevelopment.

Laravel에서 Custom Blade Directives를 어떻게 작성하고 사용합니까?Laravel에서 Custom Blade Directives를 어떻게 작성하고 사용합니까?Mar 17, 2025 pm 02:50 PM

이 기사는 Laravel에서 사용자 정의 블레이드 지시문을 만들고 사용하여 템플릿을 향상시키는 것에 대해 설명합니다. 지침 정의, 템플릿에서이를 사용하고 대규모 프로젝트에서 관리하고 개선 된 코드 재사용 성 및 R과 같은 이점을 강조합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse용 SAP NetWeaver 서버 어댑터

Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

DVWA

DVWA

DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

SublimeText3 영어 버전

SublimeText3 영어 버전

권장 사항: Win 버전, 코드 프롬프트 지원!

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기