bekas perkhidmatan
- Pengikatan asas
- Pengikatan mudah
- Ikat satu tong
- Ikat nilai asas
- Ikat antara muka ke pelaksanaan
- Pengikatan konteks
- tag
- Pengikatan lanjutan
- Kaedah Analisis
- secara automatik menyuntik
- peristiwa bekas
- PSR -11
- Pengenalan kepada bekas servis
- Selesaikan
- Pengenalan
- Bekas perkhidmatan Laravel ialah alat yang berkuasa untuk mengurus kebergantungan kelas dan melaksanakan suntikan kebergantungan. Suntikan kebergantungan istilah mewah pada asasnya bermakna kebergantungan kelas "disuntik" ke dalam kelas melalui pembina atau, dalam beberapa kes, kaedah "penetap". Mari kita lihat contoh mudah:
<?php namespace App\Http\Controllers; use App\User; use App\Repositories\UserRepository; use App\Http\Controllers\Controller; class UserController extends Controller{ /** * 用户存储库的实现. * * @var UserRepository */ protected $users; /** * 创建新的控制器实例. * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * 显示指定用户的 profile. * * @param int $id * @return Response */ public function show($id) { $user = $this->users->find($id); return view('user.profile', ['user' => $user]); } }
- Dalam contoh ini, pengawal
UserController
perlu mendapatkan pengguna daripada sumber data. Oleh itu, kita perlu menyuntik perkhidmatan yang boleh mendapatkan pengguna. Dalam konteks semasa,UserRepository
kami berkemungkinan besar menggunakan Eloquent untuk mendapatkan maklumat pengguna daripada pangkalan data. Walau bagaimanapun, kerana repositori disuntik, kita boleh menukarnya dengan mudah kepada pelaksanaan lain. Kemudahan kaedah suntikan ini ialah apabila kami menulis ujian untuk aplikasi kami, kami juga boleh dengan mudah "mengejek" atau mencipta pelaksanaan mayaUserRepository
. Jika anda ingin membina aplikasi berskala besar yang berkuasa, satu perkara yang penting: pemahaman mendalam tentang bekas perkhidmatan Laravel. Sudah tentu, perkara yang sama berlaku untuk menyumbang kepada kod teras Laravel. - Service binding
Basic binding
Oleh kerana kebanyakan bekas perkhidmatan pengguna berdaftar dengan perkhidmatan pembekal, jadi kebanyakan contoh di bawah menunjukkan penggunaan bekas dalam pembekal perkhidmatan.
- Pengikatan Lanjutan
Pengikatan mudah
Dalam pembekal perkhidmatan, anda sentiasa boleh mengakses bekas melalui atribut$this->app
. Kita boleh mendaftarkan pengikatan melalui kaedah bind
bagi bekas Parameter pertama kaedah bind
ialah nama kelas/antara muka yang akan diikat, dan parameter kedua ialah pengembalian. kelas. Contoh Penutupan
: $this->app->bind('HelpSpot\API', function ($app) { return new HelpSpot\API($app->make('HttpClient')); });Perhatikan bahawa kami menerima bekas itu sendiri sebagai parameter kepada penghurai. Kami kemudiannya boleh menggunakan bekas untuk menyelesaikan sub-bergantungan objek yang sedang dibina.
Ikat satu
Kaedah$this->app->singleton('HelpSpot\API', function ($app) { return new HelpSpot\API($app->make('HttpClient')); });
Binding instance
Anda juga boleh mengikat contoh objek sedia ada pada bekas menggunakan kaedah instance
. Contoh yang diberikan akan sentiasa dikembalikan ke bekas pada panggilan berikutnya: instance
方法将现有对象实例绑定到容器中。给定的实例会始终在随后的调用中返回到容器中:
$api = new HelpSpot\API(new HttpClient); $this->app->instance('HelpSpot\API', $api);
绑定基本值
当你有一个类不仅需要接受一个注入类,还需要注入一个基本值(比如整数)。你可以使用上下文绑定来轻松注入你的类需要的任何值:
$this->app->when('App\Http\Controllers\UserController') ->needs('$variableName') ->give($value);
绑定接口到实现
服务容器有一个很强大的功能,就是支持绑定接口到给定的实现。例如,如果我们有个 EventPusher
接口 和一个 RedisEventPusher
实现。一旦我们写完了 EventPusher
接口的 RedisEventPusher
实现,我们就可以在服务容器中注册它,像这样:
$this->app->bind( 'App\Contracts\EventPusher', 'App\Services\RedisEventPusher' );
这么做相当于告诉容器:当一个类需要实现 EventPusher
时,应该注入 RedisEventPusher
。现在我们就可以在构造函数或者任何其他通过服务容器注入依赖项的地方使用类型提示注入 EventPusher
接口:
use App\Contracts\EventPusher; /** * Create a new class instance. * * @param EventPusher $pusher * @return void */ public function __construct(EventPusher $pusher){ $this->pusher = $pusher; }
上下文绑定
有时你可能有两个类使用了相同的接口,但你希望各自注入不同的实现。例如, 有两个控制器可能依赖了 IlluminateContractsFilesystemFilesystem
契约. Laravel 提供了一个简单的,优雅的接口来定义这个行为:
use Illuminate\Support\Facades\Storage; use App\Http\Controllers\PhotoController; use App\Http\Controllers\VideoController; use Illuminate\Contracts\Filesystem\Filesystem; $this->app->when(PhotoController::class) ->needs(Filesystem::class) ->give(function () { return Storage::disk('local'); }); $this->app->when([VideoController::class, UploadController::class]) ->needs(Filesystem::class) ->give(function () { return Storage::disk('s3'); });
标记
有时候,你可能需要解析某个 “分类” 下的所有绑定。 比如, 你可能正在构建一个报表的聚合器,它接收一个包含不同 Report
接口实现的数组。注册 Report
实现之后,你可以使用 tag
方法给他们分配一个标签:
$this->app->bind('SpeedReport', function () { // }); $this->app->bind('MemoryReport', function () { // }); $this->app->tag(['SpeedReport', 'MemoryReport'], 'reports');
一旦服务被标记,你就可以通过 tagged
方法轻松地解析它们:
$this->app->bind('ReportAggregator', function ($app) { return new ReportAggregator($app->tagged('reports')); });
扩展绑定
extend
方法可以修改已解析的服务。比如,当一个服务被解析后,你可以添加额外的代码来修饰或者配置它。 extend
方法接受一个闭包,该闭包唯一的参数就是这个服务, 并返回修改过的服务:
$this->app->extend(Service::class, function ($service) { return new DecoratedService($service); });
解析实例
make
方法
你可以使用 make
方法从容器中解析出类实例。 make
方法接收你想要解析的类或接口的名字:
$api = $this->app->make('HelpSpot\API');
如果你的代码处于无法访问 $app
变量的位置,则可用全局辅助函数 resolve
来解析:
$api = resolve('HelpSpot\API');
如果类依赖不能通过容器解析,你可以通过将它们作为关联数组作为 makeWith
$api = $this->app->makeWith('HelpSpot\API', ['id' => 1]);Mengikat nilai asas
<?php namespace App\Http\Controllers; use App\Users\Repository as UserRepository; class UserController extends Controller{ /** * The user repository instance. */ protected $users; /** * Create a new controller instance. * * @param UserRepository $users * @return void */ public function __construct(UserRepository $users) { $this->users = $users; } /** * Show the user with the given ID. * * @param int $id * @return Response */ public function show($id) { // } }🎜🎜
Mengikat antara muka pada pelaksanaan
🎜Perkhidmatan Ciri yang sangat berkuasa daripada bekas ialah mereka menyokong antara muka yang mengikat kepada pelaksanaan yang diberikan. Contohnya, jika kami mempunyai antara mukaEventPusher
dan pelaksanaan RedisEventPusher
. Sebaik sahaja kami telah menulis pelaksanaan RedisEventPusher
antara muka EventPusher
, kami boleh mendaftarkannya dalam bekas perkhidmatan, seperti ini: 🎜$this->app->resolving(function ($object, $app) { // Called when container resolves object of any type... }); $this->app->resolving(HelpSpot\API::class, function ($api, $app) { // Called when container resolves objects of type "HelpSpot\API"... });🎜Ini sama dengan memberitahu bekas: bila kelas Apabila anda perlu melaksanakan
EventPusher
, anda harus menyuntik RedisEventPusher
. Kini kita boleh menggunakan petunjuk jenis untuk menyuntik antara muka EventPusher
dalam pembina atau mana-mana tempat lain yang kebergantungan disuntik melalui bekas perkhidmatan: 🎜use Psr\Container\ContainerInterface; Route::get('/', function (ContainerInterface $container) { $service = $container->get('Service'); // });🎜🎜🎜< h3> Pengikatan konteks🎜Kadangkala anda mungkin mempunyai dua kelas yang menggunakan antara muka yang sama, tetapi anda ingin menyuntik pelaksanaan berbeza ke dalam setiap kelas. Contohnya, dua pengawal mungkin bergantung pada kontrak
IlluminateContractsFilesystemFilesystem
Laravel menyediakan antara muka yang ringkas dan elegan untuk mentakrifkan tingkah laku ini: 🎜rrreee🎜🎜🎜Mark🎜Kadangkala, anda mungkin perlu menghuraikan semua pengikatan di bawah "kategori" tertentu. Sebagai contoh, anda mungkin membina pengagregat laporan yang menerima tatasusunan pelaksanaan berbeza antara muka Laporan
. Selepas mendaftarkan pelaksanaan Report
, anda boleh menetapkan teg kepada mereka menggunakan kaedah tag
: 🎜rrreee🎜Setelah perkhidmatan ditandakan, anda boleh menetapkannya melalui tag< /code> Kaedah untuk menghuraikannya dengan mudah: 🎜rrreee🎜🎜🎜Melanjutkan Pengikatan
🎜lanjutkan
kaedah boleh mengubah suai perkhidmatan yang diselesaikan. Sebagai contoh, selepas perkhidmatan diselesaikan, anda boleh menambah kod tambahan untuk menghiasi atau mengkonfigurasinya. Kaedah lanjutkan
menerima penutupan yang hanya parameternya ialah perkhidmatan dan mengembalikan perkhidmatan yang diubah suai: 🎜rrreee🎜🎜🎜Contoh penyelesaian< /h2>🎜< a name="the-make-method">🎜🎜🎜make
kaedah 🎜🎜Anda boleh menggunakan kaedah make
untuk menyelesaikan kejadian kelas daripada bekas. Kaedah make
menerima nama kelas atau antara muka yang anda ingin selesaikan: 🎜rrreee🎜Jika kod anda berada dalam kedudukan yang anda tidak boleh mengakses pembolehubah $app
, anda boleh menggunakan fungsi pembantu global< code>resolve untuk menyelesaikan: 🎜rrreee🎜Jika kebergantungan kelas tidak dapat diselesaikan oleh bekas, anda boleh menyuntiknya sebagai tatasusunan bersekutu sebagai parameter makeWith
kaedah: 🎜rrreee🎜🎜🎜🎜Suntikan automatik
Selain itu, dan yang lebih penting, anda hanya boleh menggunakan "petua jenis" untuk menyuntik kebergantungan yang perlu diselesaikan oleh bekas dalam pembina kelas, termasuk pengawal, pendengar acara, tugas baris gilir, perisian tengah, dsb. . Sebenarnya, ini adalah cara kebanyakan objek harus diselesaikan oleh bekas.
Sebagai contoh, anda boleh menambah pembayang jenis repositori dalam pembina pengawal, dan kemudian repositori akan dihuraikan secara automatik dan disuntik ke dalam kelas:
rrreeeperistiwa bekas
Setiap kali objek perkhidmatan akan mencetuskan acara, anda boleh menggunakan kaedah menyelesaikan
untuk mendengar acara ini: resolving
方法监听这个事件 :
rrreee正如你所看到的,被解析的对象将会被传入回调函数,这使得你能够在对象被传给调用者之前给它设置额外的属性。
PSR-11
Laravel 的服务容器实现了 PSR-11 接口。因此,你可以使用 PSR-11 容器 『接口类型提示』 来获取 Laravel 容器的实例:
rrreee如果无法解析给定的标识符,则将会引发异常。未绑定标识符时,会抛出 PsrContainerNotFoundExceptionInterface
异常。如果标识符已绑定但无法解析,会抛出 PsrContainerContainerExceptionInterface
rrreee
Seperti yang anda lihat, objek yang dihuraikan akan dihantar ke dalam fungsi panggil balik, yang membolehkan anda Menetapkan sifat tambahan sebelum menyampaikannya kepada pemanggil.
Melanjutkan Pengikatan
🎜make
kaedah 🎜🎜Anda boleh menggunakan kaedah make
untuk menyelesaikan kejadian kelas daripada bekas. Kaedah make
menerima nama kelas atau antara muka yang anda ingin selesaikan: 🎜rrreee🎜Jika kod anda berada dalam kedudukan yang anda tidak boleh mengakses pembolehubah $app
, anda boleh menggunakan fungsi pembantu global< code>resolve untuk menyelesaikan: 🎜rrreee🎜Jika kebergantungan kelas tidak dapat diselesaikan oleh bekas, anda boleh menyuntiknya sebagai tatasusunan bersekutu sebagai parameter makeWith
kaedah: 🎜rrreee🎜🎜🎜🎜Suntikan automatik
menyelesaikan
untuk mendengar acara ini: resolving
方法监听这个事件 :PsrContainerNotFoundExceptionInterface
异常。如果标识符已绑定但无法解析,会抛出 PsrContainerContainerExceptionInterface
rrreeePsrContainerNotFoundExceptionInterface
dilemparkan. Jika pengecam terikat tetapi tidak dapat diselesaikan, pengecualian PsrContainerContainerExceptionInterface
dilemparkan. 🎜🎜Artikel ini pertama kali diterbitkan di laman web 🎜LearnKu.com🎜. 🎜🎜