$this->app->singleton() 在 Laravel 中如何工作?

Scr*_*ver 6 php laravel

在我的 laravel 项目中,我有以下接口、存储库和控制器。

这是界面

interface TrainingClassTypeInterfaces
{
    public function updateTrainingClassType($id, $request);
} 
Run Code Online (Sandbox Code Playgroud)

这是存储库

use App\Models\Trainings\AppTrainingClassType;
class TrainingClassTypeEloquent implements TrainingClassTypeInterfaces
    {
        protected $model;
    
        public function __construct(AppTrainingClassType $appTrainingClassType)
        {
            $this->model = $appTrainingClassType;
        }
    
        public  function updateTrainingClassType($id, $request)
        {
            $response = false;
            $isUpdated = $this->model::where('training_class_id',$id)->update([
                'app_id' => $request->app_id
            ]);
            .... 
        }
    
    }
Run Code Online (Sandbox Code Playgroud)

这是控制器

class TrainingClassTypesController extends \TCG\Voyager\Http\Controllers\VoyagerBaseController
{
    protected  $trainingService;
    public function __construct(TrainingClassTypeEloquent $trainingClassTypeInterfaces) {
        $this->trainingService = $trainingClassTypeInterfaces;
    }

    public function insertOrUpdate()
    {
        ...
        $this->trainingService->updateTrainingClassType($id, $request);
        ..
    }

}
Run Code Online (Sandbox Code Playgroud)

到这里一切正常

正如你所看到的,我在内部使用 TrainingClassTypeEloquent 的方法TrainingClassTypesController。但它返回了类似的错误

Argument 1 passed to ...::__construct() must be an instance of

基本上它要求我将模型的实例放入TrainingClassTypeEloquent类中。然后我做了如下

$TCTypes = new AppTrainingClassType();
$TCT = new TrainingClassTypeEloquent($TCTypes);
$TCT->updateTrainingClassType($id, $request);
Run Code Online (Sandbox Code Playgroud)

工作正常,但我很困惑这种方法不正确,应该有一些正确的方法。

谷歌搜索后,我找到了另一个解决方案,即单例绑定,然后我尝试在 AppServiceProvider 中执行以下操作

$this->app->singleton(
            \App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeInterfaces::class,
            \App\Services\Voyager\Eloquent\TrainingClassType\TrainingClassTypeEloquent::class
        );
Run Code Online (Sandbox Code Playgroud)

添加此单例绑定后,我注意到脚本可以正常工作,而无需向TrainingClassTypeEloquent类中提供模型实例。

我想知道它$this->app->singleton()是如何工作的,这样我的概念就会很清楚。如果有人知道,请指导我。

太感谢了

unc*_*exo 5

这都是关于将服务绑定服务容器

方法有什么作用$this->app->singleton();

单例方法将类或接口绑定到服务容器中,以便 Laravel 可以保持依赖关系(当使用接口作为构造函数参数时)。

(实际上Singleton是一种设计模式。Singleton实现在后续调用中总是返回相同的对象,而不是一个新的实例)。所以$this->app->singleton();方法一次又一次返回同一个对象。

需要注意的是 Laravel 文档说:

如果类不依赖于任何接口,则无需将类绑定到容器中。容器不需要被告知如何构建这些对象,因为它可以使用反射自动解析这些对象。

但是您的控制器类依赖于接口,因此需要通知容器并且要执行此操作,您需要使用此$this->app->singleton();方法,但还有其他方法。

同时,这又TrainingClassTypeEloquent::class具有AppTrainingClassType::class. 但在这种情况下,我们不需要担心这一点,因为 Laravel 使用Reflection API来维护其依赖关系,因为该类不像TrainingClassTypesController::class类那样使用接口。

完成将服务绑定到容器后,Laravel 会自动将服务作为使用接口的参数放入构造函数方法中。

我希望这对你有帮助。您可能会从这个答案中找到更多帮助。


cba*_*ier 2

您需要注册 TrainingClassTypeEloquent

$this->app->singleton(TrainingClassTypeInterfaces::class, static function ($app) {
    return new TrainingClassTypeEloquent(new AppTrainingClassType());
});
Run Code Online (Sandbox Code Playgroud)

然后你可以将它注入到你的控制器中

public function insertOrUpdate(TrainingClassTypeInterfaces $trainingService, $id)
{
    $trainingService->updateTrainingClassType($id, request());
}

Run Code Online (Sandbox Code Playgroud)