无法将类实例传递给构造函数

Posted

技术标签:

【中文标题】无法将类实例传递给构造函数【英文标题】:Can't pass class instance to constructor 【发布时间】:2014-04-15 19:10:29 【问题描述】:

我有一个 User eloquent 模型,它在其构造函数中接收 UserMailer 类的一个实例,但我得到了这个错误

Argument 1 passed to User::__construct() must be an instance of TrainerCompare\Mailers\UserMailer, none given, called in /var/www/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 631 and defined

我理解错误,但无法弄清楚我做错了什么,但我不了解命名空间和作曲家类映射与 psr0 自动加载的关系。我记得使用 composer dump-autoload 所以不是这样的

相关文件夹结构

composer.json
app/
  models/
    User.php
  TrainerCompare/
    Mailers/
      Mailer.php
      UserMailer.php
    Services/
      Validation/

composer.json 自动加载部分。当我添加您可以在 TrainerCompare/ 中看到的验证服务时,psr-0 部分就在那里,这些类工作得很好。我按照我正在遵循的教程将 app/TrainerCompare/Mailers 添加到类映射中以加载邮件程序类

"autoload": 
        "classmap": [
            "app/commands",
            "app/controllers",
            "app/models",
            "app/database/migrations",
            "app/database/seeds",
            "app/tests/TestCase.php",
            "app/tests/helpers",
            "app/TrainerCompare/Mailers"
        ],
        "psr-0":
            "TrainerCompare": "app/"
        
    

用户.php

<?php

use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
use TrainerCompare\Mailers\UserMailer as Mailer;

class User extends BaseModel implements UserInterface, RemindableInterface

    protected $mailer;

    public function __construct(Mailer $mailer)
    
        $this->mailer = $mailer;
    

Mailer.php

<?php namespace TrainerCompare\Mailers;

use Mail;

/**
* Email mailing class
*/
abstract class Mailer


    public function __construct()
    
        # code...
    

    public function sendTo($user, $subject, $view, $data = [])
    
        Maill::send($view, $data, function ($message) use ($user, $subject) 
            $message->to($user->email)
                    ->subject($subject);
        );
    

UserMailer.php

<?php namespace TrainerCompare\Mailers;

use User;

/**
* User Mailer Class
*/
class UserMailer extends Mailer


    public function __construct()
    
        # code...
    

    public function welcome($user)
    
        $view = 'emails.users.welcome';
        $data = [];
        $subject = 'Welcome to Laracsts';

        return $this->sendTo($user, $subject, $view, $data);
    

【问题讨论】:

你也可以发布你的 Model.php 吗? 【参考方案1】:

Eloquent(重新)通过调用在内部创建自己:

new static

一个例子是创建一个新的查询:

return with(new static)->newQuery();

我不确定在这种情况下自动依赖解析是否可以工作,它应该总是在 laravel 中工作,但由于它也有它自己的构造方法,你至少必须转发一个对它的调用并支持$attribute参数:

public function __construct(array $attributes = array(), Mailer $mailer)

    $this->mailer = $mailer;

    parent::__construct($attributes);

编辑

打开一个问题了解一下:https://github.com/laravel/framework/issues/3862

编辑 2

正如我在评论中所说,您最好创建一个服务,正如您自己所指出的那样,是一个更好的应用程序设计。您不应该使用您的模型来发送电子邮件。接收用户模型(或只是姓名和电子邮件)并将消息发送给该用户的服务将是更好的选择。

Taylor Otwell 在本期中给出的答案:

模型并不是真的要以这种方式将依赖项注入其中。 我猜这只是 ActiveRecord 风格的 ORM 的风格。 我建议将用户传递给 Mailer 类或类似的东西。 或者,如果您对它感到满意,您可以使用 App::make 来获取 来自模型实例的邮件,尤其是当您只需要该依赖项时 来自单一方法。

【讨论】:

这是有道理的,当我创建构造函数时,我确实认为我以前从未见过它,它可能不起作用,但是当错误发生时我没有连接点。从商店控制器方法中调用这些“服务”是否可以/最佳实践? 这样做应该没问题,这是一种非常基本的类扩展,但如果 Taylor 无法解决它,你最好创建一个服务,正如你所指出的那样更好的应用程序设计。人们会说你不应该使用你的模型来发送电子邮件。接收用户模型(或只是姓名和电子邮件)并将消息发送给该用户的服务会更好。

以上是关于无法将类实例传递给构造函数的主要内容,如果未能解决你的问题,请参考以下文章

在类构造函数中将此指针传递给 CreateThread 在线程过程中表现得很奇怪

将模板类实例传递给另一个类的构造函数

无法从构造函数中将数组值传递给向量

禁用复制构造函数和赋值运算符时将引用实例传递给静态方法

当映射变量传递给不同实例的构造函数时,所有实例成员变量都会更新为映射的最新值[重复]

来自 C++ 的 QQuickItem 实例化和设置难题(不允许将任何内容传递给构造函数)