laravel 容器,支付模块设计

新手上路,请多包涵

假设我现在需要做一个支付服务,那么我先设计一个接口

interface PayInterface{
    public function pay(Order $order) : string;
}

然后实现这个接口

class WeiXinPay implements PayInterface{
    protected $appID = "xxxx";
    protected $mchID = "xxxx";
    protected $mchKey = "xxxx";

    public function pay(Order $order) :string{
        //具体实现
    }
}

然后在PayServiceProvider中注册这个服务

$this->app->bind(PayInterface::class , WeiXinPay::class);

写个单元测试试试

public function testPay(){
        $orderSn = Strings::randomString('NUMBER+',12);
        $order = factory(Order::class)->make([
            'sn' => $orderSn,
            'amount' => 1,
            'attach' => 1,
        ]);
        
        /**
         * @var $service PayInterface
        */
        $service = $this->app->make(PayInterface::class);
        
        $res = $service->pay($order);
        $this->assertIsString($res);
    }

这里看上去没有问题,一切都如预期一样。
但是很快需求就变了,WeiXinPay的三个属性appID,mchID,mchKey不能写死,需要从外部读取。我便开始改造我的代码。
如何优雅的得到WeiXinPay依赖的三个参数呢? 我想到了再定义一个接口,这样:

interface PaySettingsInterface {
    public function getSettings() : array;
}

然后实现他

//从env文件读取
class EnvPaySettings implements PaySettingsInterface{
    public function getSettings() : array{
        return [
            'app_id' => 'xxxx',
            'app_secret' => 'yyyyy',
            'key' => 'zzzz'
        ];
    }
}

//从数据库读取
class DataBasePaySettings implements PaySettingsInterface{
    public function getSettings() : array{
        $settings = DB::table('pay_settings')->get();
        return $settings;
    }
}

修改我的WeiXinPay

class WeiXinPay implements PayInterface{

    protected $settings;

    public __construct(PaySettingsInterface $settings){
        $this->settings = $settings->getSettings();
    }

    public function pay(Order $order) :string{
        //具体实现
    }
}

修改PayServiceProvider

//这一行我可以方便的随时修改EnvPaySetting为DataBasePaySettings
$this->app->bind(PaySettingsInterface::class,EnvPaySettings::class);
$this->app->bind(PayInterface::class , WeiXinPay::class);

再跑我的单元测试

public function testPay(){
        $orderSn = Strings::randomString('NUMBER+',12);
        $order = factory(Order::class)->make([
            'sn' => $orderSn,
            'amount' => 1,
            'attach' => 1,
        ]);
        
        /**
         * @var $service PayInterface
        */
        $service = $this->app->make(PayInterface::class);
        
        $res = $service->pay($order);
        $this->assertIsString($res);
    }

一切还是没变,都如预期一样,我的单元测试代码一行都没有改。
但是,又有新的需求出现了,老板说,支付的时候要每个收款人的mchID,appID,appKey都不一样。
于是我开始改我的代码,第一个思路是再写一个UserPaySettings,说干就干

class User extends Model{
    //model 的其它定义

    public function settings(){
       $settings = //获取settings的代码
       return $settings;
    }
}


//从用户关联读取
class UserPaySettings implements PaySettingsInterface{
    protected $user;
    public function __construct(User $user){
       $this->user = $user;
    }

    public function getSettings() : array{
        $settings = $this->user->settings();
        return $settings;
    }
}

好了。我天真的再去修改我的PayServiceProvider,把之前的EnvPaySettings替换成UserPaySettings

$this->app->bind(PaySettingsInterface::class,UserPaySettings::class);
$this->app->bind(PayInterface::class , WeiXinPay::class);

再天真的跑一下我的单元测试,还是一行代码都没改

public function testPay(){
        $orderSn = Strings::randomString('NUMBER+',12);
        $order = factory(Order::class)->make([
            'sn' => $orderSn,
            'amount' => 1,
            'attach' => 1,
        ]);
       
        /**
         * @var $service PayInterface
        */
        $service = $this->app->make(PayInterface::class);
        
        $res = $service->pay($order);
        $this->assertIsString($res);
    }

然后就报错了。因为UserPaySettings是要注入一个User模型的
怎么办,通过容器貌似已经无法再自动注入了,因为传递进去的User模型是变化的。

阅读 2.1k
1 个回答
$this->app->bind(PaySettingsInterface::class, function () {
    return new UserPaySettings(User::find(rand(1, 5))->get());
});
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题