Rumah > rangka kerja php > Laravel > Apakah bekas perkhidmatan laravel

Apakah bekas perkhidmatan laravel

青灯夜游
Lepaskan: 2022-02-14 16:31:39
asal
2798 orang telah melayarinya

Dalam laravel, bekas perkhidmatan ialah alat yang berkuasa untuk mengurus kebergantungan kelas dan melaksanakan suntikan kebergantungan. Apabila aplikasi perlu menggunakan perkhidmatan tertentu, bekas perkhidmatan akan menyelesaikan perkhidmatan dan secara automatik menyelesaikan kebergantungan antara perkhidmatan, dan kemudian menyerahkannya kepada aplikasi untuk digunakan.

Apakah bekas perkhidmatan laravel

Persekitaran pengendalian tutorial ini: sistem Windows 7, versi Laravel 6, komputer Dell G3.

Apakah itu bekas perkhidmatan?

Bekas perkhidmatan Laravel ialah alat yang berkuasa untuk mengurus kebergantungan kelas dan melaksanakan suntikan kebergantungan. Istilah suntikan kebergantungan kelihatan mewah di permukaan, tetapi pada asasnya ia bermaksud: "menyuntik" kebergantungan kelas ke dalam kelas melalui pembina, atau dalam beberapa kes melalui kaedah "setter".

Modul fungsional dalam Laravel seperti Route, Eloquent ORM, Request, Response, dsb. sebenarnya disediakan oleh modul kelas yang tiada kaitan dengan teras Kelas ini adalah dari pendaftaran hingga instantiasi, dan akhirnya digunakan oleh kami sebenarnya adalah tanggungjawab bekas servis laravel.

Terdapat dua konsep 控制反转(IOC) dan 依赖注入(DI) dalam bekas perkhidmatan:

Suntikan kebergantungan dan penyongsangan kawalan adalah perihalan berbeza bagi perkara yang sama , mereka menerangkan sudut yang berbeza. Suntikan ketergantungan diterangkan dari perspektif aplikasi Aplikasi bergantung pada bekas untuk mencipta dan menyuntik sumber luaran yang diperlukan. Penyongsangan kawalan diterangkan dari perspektif bekas Bekas mengawal aplikasi, dan bekas menyuntik sumber luaran yang diperlukan oleh aplikasi ke dalam aplikasi secara terbalik.

Dalam Laravel, rangka kerja mengikat pelbagai perkhidmatannya kepada bekas perkhidmatan Kami juga boleh mengikat perkhidmatan tersuai pada bekas. Apabila aplikasi perlu menggunakan perkhidmatan tertentu, bekas perkhidmatan akan menghuraikan perkhidmatan, secara automatik menyelesaikan kebergantungan antara perkhidmatan, dan kemudian menyerahkannya kepada aplikasi untuk digunakan.

Mari bincangkan cara pengikatan dan penghuraian perkhidmatan dilaksanakan dalam Laravel.

Pengikatan perkhidmatan

Kaedah yang biasa digunakan untuk mengikat perkhidmatan pada bekas termasuk instance, bind, singleton dan alias. Mari kita lihat mereka secara berasingan.

contoh

Mengikat objek sedia ada pada bekas perkhidmatan Apabila perkhidmatan itu kemudiannya diselesaikan dengan nama, bekas itu akan sentiasa mengembalikan contoh terikat.

$api = new HelpSpot\API(new HttpClient);
$this->app->instance('HelpSpot\Api', $api);
Salin selepas log masuk

akan mendaftarkan objek dalam atribut $instnces bagi bekas perkhidmatan

[
     'HelpSpot\Api' => $api//$api是API类的对象,这里简写了
 ]
Salin selepas log masuk

ikat

Ikat perkhidmatan to Service container

mempunyai tiga kaedah pengikatan:

1.

$this->app->bind('HelpSpot\API', null);
Salin selepas log masuk
2 dan pelaksanaan

$this->app->bind('HelpSpot\API', function () {
    return new HelpSpot\API();
});//闭包直接提供类实现方式
$this->app->bind('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app->make('HttpClient'));
});//闭包返回需要依赖注入的类
Salin selepas log masuk
Dalam kes pertama, sebenarnya, dalam kaedah bind, penutupan dijana untuk perkhidmatan melalui getClosure() sebelum mengikat perkhidmatan kaedah mengikat.

$this->app->bind('Illuminate\Tests\Container\IContainerContractStub', 'Illuminate\Tests\Container\ContainerImplementationStub');
Salin selepas log masuk
bind mendaftarkan perkhidmatan ke dalam atribut $bindings bagi bekas perkhidmatan seperti ini:

public function bind($abstract, $concrete = null, $shared = false)
{
    $abstract = $this->normalize($abstract);
    
    $concrete = $this->normalize($concrete);
    //如果$abstract为数组类似['Illuminate/ServiceName' => 'service_alias']
    //抽取别名"service_alias"并且注册到$aliases[]中
    //注意:数组绑定别名的方式在5.4中被移除,别名绑定请使用下面的alias方法
    if (is_array($abstract)) {
        list($abstract, $alias) = $this->extractAlias($abstract);

        $this->alias($abstract, $alias);
    }

    $this->dropStaleInstances($abstract);

    if (is_null($concrete)) {
        $concrete = $abstract;
    }
    //如果只提供$abstract,则在这里为其生成concrete闭包
    if (! $concrete instanceof Closure) {
        $concrete = $this->getClosure($abstract, $concrete);
    }

    $this->bindings[$abstract] = compact('concrete', 'shared');

    if ($this->resolved($abstract)) {
        $this->rebound($abstract);
    }
}


protected function getClosure($abstract, $concrete)
{
    // $c 就是$container,即服务容器,会在回调时传递给这个变量
    return function ($c, $parameters = []) use ($abstract, $concrete) {
        $method = ($abstract == $concrete) ? 'build' : 'make';

        return $c->$method($concrete, $parameters);
    };
}
Salin selepas log masuk

singleton

$bindings = [
    'HelpSpot\API' =>  [//闭包绑定
        'concrete' => function ($app, $paramters = []) {
            return $app->build('HelpSpot\API');
        },
        'shared' => false//如果是singleton绑定,这个值为true
    ]        
    'Illuminate\Tests\Container\IContainerContractStub' => [//接口实现绑定
        'concrete' => 'Illuminate\Tests\Container\ContainerImplementationStub',
        'shared' => false
    ]
]
Salin selepas log masuk

singleton Kaedah ialah varian kaedah bind Ia mengikat kelas atau antara muka yang hanya perlu dihuraikan sekali ke bekas, dan kemudian perkhidmatan akan mengembalikan contoh yang sama untuk panggilan berikutnya ke bekas

public function singleton($abstract, $concrete = null)
{
    $this->bind($abstract, $concrete, true);
}
Salin selepas log masuk
alias

Daftar perkhidmatan dan alias perkhidmatan ke bekas:

Kaedah alias berguna dalam kaedah bind yang dinyatakan di atas alias perkhidmatan dan kelas perkhidmatan kepada perkhidmatan Dalam atribut $aliases bagi bekas.

Contohnya:
public function alias($abstract, $alias)
{
    $this->aliases[$alias] = $this->normalize($abstract);
}
Salin selepas log masuk

Selepas mengikat perkhidmatan, anda boleh menghuraikan objek perkhidmatan melalui

$this->app->alias('\Illuminate\ServiceName', 'service_alias');
Salin selepas log masuk
apabila menggunakannya, jadi anda tidak perlu tuliskannya apabila membuat Nama kelas yang lebih panjang itu telah meningkatkan pengalaman menggunakan kaedah buat.

$this->app->make('service_alias');
Salin selepas log masuk

Penghuraian perkhidmatan

buat: Parsing objek perkhidmatan daripada bekas perkhidmatan Kaedah ini menerima nama kelas atau nama antara muka yang anda mahu huraikan . Sebagai parameter

, melalui menyusun kaedah membuat, kami mendapati bahawa fungsi kaedah binaan adalah untuk membina objek perkhidmatan yang dihuraikan . (Refleksi kelas PHP digunakan semasa proses pembinaan untuk melaksanakan suntikan kebergantungan perkhidmatan)

/**
 * Resolve the given type from the container.
 *
 * @param  string  $abstract
 * @param  array   $parameters
 * @return mixed
 */
public function make($abstract, array $parameters = [])
{
    //getAlias方法会假定$abstract是绑定的别名,从$aliases找到映射的真实类型名
    //如果没有映射则$abstract即为真实类型名,将$abstract原样返回
    $abstract = $this->getAlias($this->normalize($abstract));
    // 如果服务是通过instance()方式绑定的,就直接解析返回绑定的service
    if (isset($this->instances[$abstract])) {
        return $this->instances[$abstract];
    }
    // 获取$abstract接口对应的$concrete(接口的实现)
    $concrete = $this->getConcrete($abstract);
    if ($this->isBuildable($concrete, $abstract)) {
        $object = $this->build($concrete, $parameters);
    } else {
        //如果时接口实现这种绑定方式,通过接口拿到实现后需要再make一次才能
        //满足isBuildable的条件 ($abstract === $concrete)
        $object = $this->make($concrete, $parameters);
    }
    foreach ($this->getExtenders($abstract) as $extender) {
        $object = $extender($object, $this);
    }
    //如果服务是以singleton方式注册进来的则,把构建好的服务对象放到$instances里,
    //避免下次使用时重新构建
    if ($this->isShared($abstract)) {
        $this->instances[$abstract] = $object;
    }
    $this->fireResolvingCallbacks($abstract, $object);
    $this->resolved[$abstract] = true;
    return $object;
}
protected function getConcrete($abstract)
{
    if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
        return $concrete;
    }
    // 如果是$abstract之前没有注册类实现到服务容器里,则服务容器会认为$abstract本身就是接口的类实现
    if (! isset($this->bindings[$abstract])) {
        return $abstract;
    }
    return $this->bindings[$abstract]['concrete'];
}
protected function isBuildable($concrete, $abstract)
{        
    return $concrete === $abstract || $concrete instanceof Closure;
}
Salin selepas log masuk
Bekas perkhidmatan ialah teras laravel. Ia boleh membantu kami menyelesaikan saling kebergantungan antara objek melalui suntikan kebergantungan. dan melalui penyongsangan kawalan, ia diserahkan kepada luar untuk mentakrifkan gelagat tertentu (Laluan, Fasih, ini adalah modul luaran, dan mereka mentakrifkan spesifikasi gelagat mereka sendiri. Bekas perkhidmatan bertanggungjawab ke atas kelas ini daripada pendaftaran kepada instantiasi untuk kegunaan anda).

Untuk kelas yang diekstrak oleh bekas, ia mesti didaftarkan terlebih dahulu dengan bekas. Oleh kerana laravel memanggil kontena ini sebagai bekas perkhidmatan, jika kita memerlukan perkhidmatan, kita mesti mendaftar dan mengikat perkhidmatan ke kontena kemudian perkara yang menyediakan perkhidmatan dan mengikat perkhidmatan ke kontena adalah penyedia perkhidmatan (ServiceProvider). Pembekal perkhidmatan terbahagi terutamanya kepada dua bahagian, daftar (pendaftaran) dan but (but, permulaan)
public function build($concrete, array $parameters = [])
{
    // 如果是闭包直接执行闭包并返回(对应闭包绑定)
    if ($concrete instanceof Closure) {
        return $concrete($this, $parameters);
    }
    
    // 使用反射ReflectionClass来对实现类进行反向工程
    $reflector = new ReflectionClass($concrete);
    // 如果不能实例化,这应该是接口或抽象类,再或者就是构造函数是private的
    if (! $reflector->isInstantiable()) {
        if (! empty($this->buildStack)) {
            $previous = implode(', ', $this->buildStack);
            $message = "Target [$concrete] is not instantiable while building [$previous].";
        } else {
            $message = "Target [$concrete] is not instantiable.";
        }
        throw new BindingResolutionException($message);
    }
    $this->buildStack[] = $concrete;
    // 获取构造函数
    $constructor = $reflector->getConstructor();
    // 如果构造函数是空,说明没有任何依赖,直接new返回
    if (is_null($constructor)) {
        array_pop($this->buildStack);
        return new $concrete;
    }
    
    // 获取构造函数的依赖(形参),返回一组ReflectionParameter对象组成的数组表示每一个参数
    $dependencies = $constructor->getParameters();
    $parameters = $this->keyParametersByArgument(
        $dependencies, $parameters
    );
    // 构建构造函数需要的依赖
    $instances = $this->getDependencies(
        $dependencies, $parameters
    );
    array_pop($this->buildStack);
    return $reflector->newInstanceArgs($instances);
}
//获取依赖
protected function getDependencies(array $parameters, array $primitives = [])
{
    $dependencies = [];
    foreach ($parameters as $parameter) {
        $dependency = $parameter->getClass();
        // 某一依赖值在$primitives中(即build方法的$parameters参数)已提供
        // $parameter->name返回参数名
        if (array_key_exists($parameter->name, $primitives)) {
            $dependencies[] = $primitives[$parameter->name];
        } 
        elseif (is_null($dependency)) {
             // 参数的ReflectionClass为null,说明是基本类型,如'int','string'
            $dependencies[] = $this->resolveNonClass($parameter);
        } else {
             // 参数是一个类的对象, 则用resolveClass去把对象解析出来
            $dependencies[] = $this->resolveClass($parameter);
        }
    }
    return $dependencies;
}
//解析出依赖类的对象
protected function resolveClass(ReflectionParameter $parameter)
{
    try {
        // $parameter->getClass()->name返回的是类名(参数在typehint里声明的类型)
        // 然后递归继续make(在make时发现依赖类还有其他依赖,那么会继续make依赖的依赖
        // 直到所有依赖都被解决了build才结束)
        return $this->make($parameter->getClass()->name);
    } catch (BindingResolutionException $e) {
        if ($parameter->isOptional()) {
            return $parameter->getDefaultValue();
        }
        throw $e;
    }
}
Salin selepas log masuk

[Cadangan berkaitan:

tutorial video laravel

]

Atas ialah kandungan terperinci Apakah bekas perkhidmatan laravel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Label berkaitan:
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan