要求我的Laravel 4软件包被用户“扩展”以便使用它是一种好习惯吗?

时间:2013-12-31 16:25:26

标签: php laravel laravel-4 package extends

我可以想到创建一个完成目标的Laravel 4软件包有两种方法:

要求软件包的用户对其进行扩展:

// YourCoolService.php

class YourCoolService extends MyCoolPackage {

      // add the appropiate properties & methods 
      // that MyCoolPackage will expect to use

}


// YourCoolController.php

      ...

      // Example of how it would be called
      $output = YourCoolService::make()->withInput(Input::all())->render();

      ...


或者将类名称作为字符串参数传递到我的包中:

// YourCoolService.php

class YourCoolService {   // <-- no extending here

      // add the appropiate properties & methods 
      // that MyCoolPackage will expect to use

}    


// YourCoolController.php

      ...

      // The passed class name would be used to instantiate the class
      // by MyCoolPackage so that the package can use the expected 
      // properties and methods in the class
      $output = MyCoolPackage::make('Namespace\YourCoolService')->withInput(Input::all())->render();

      ...


“扩展”解决方案
PRO的

  • 来自Controller的呼叫更精简
  • 我不必直接在Controller的调用中使用命名空间。
  • 我可以创建抽象方法来通知用户他们需要实现它们(虽然这也可以通过接口完成)。

CON的

  • 用户无法扩展任何其他类,因为他们正在扩展MyCoolPackage
  • 如果我想在MyCoolPackage中有一些“帮助”函数,那么parent::helper();之类的调用将出现在整个YourCoolService类中(但我想我仍然可以像MyCoolPackage::helper();一样调用它。) / LI>

“通过班级名称”解决方案
PRO的

  • 用户无需扩展任何内容
  • 从控制器中调用显而易见的是什么包
  • 如果我想在MyCoolPackage中有一些“帮助”功能,那么我可以在YourCoolService类的任何地方称它们为MyCoolPackage::helper('foo');,并且它们来自哪里显而易见。

CON的

  • 控制器中的呼叫更长
  • 我可能需要为YourCoolService创建一个MyCoolPackage接口(虽然我不认为这是绝对必要的)
  • 控制器中的调用需要传递的字符串中的完整命名空间(是否有办法避免必须在字符串中包含命名空间?

创建一个需要在用户自己的类实现中存在属性和方法的包的最佳做法是什么?

2 个答案:

答案 0 :(得分:0)

我的观点是,最好选择composition over inheritance,并且考虑到Laravel提供的DI功能,您可以允许您的包的用户在{1}中注入MyCoolPackage的实例。对象的构造函数。那么您的make方法就不必静态调用(或者通过外观,如果是这种情况)。

基本上,我们的想法是,只要您的软件包的用户正在创建新服务,该服务类就应该为您的软件包注入一个实例。

<?php namespace Namespace;

use MyCoolPackage\MyCoolPackage;

class YourCoolService {

    protected $myCoolPackage;

    public function __construct( MyCoolPackage $package )
    {
        $this->myCoolPackage = $package;
    }

    ...

$this->myCoolPackage->make('Namespace\YourCoolController')
    ->withInput(Input::all())->render();

或者更好:

$this->myCoolPackage->make($this)->withInput(Input::all())->render();

要提供DI功能,只要MyCoolPackage在构造函数中提示类型,就需要创建一个服务提供程序来绑定IoC中MyCoolPackage\MyCoolPackage的实例。请参阅:http://laravel.com/docs/packages#service-providers

由于您要离开YourCoolService以由其他人在其他地方定义,因此除了为将要编写服务的人员提供某种范例之外,您无法做其他事情。如果你可以为他们提供一个实现的接口,那将是最好的情况,因为它会为人们编写这些服务的模板开始。

您还可以提供一个抽象基类,它将为用户提供所有其他实现可以选择覆盖与否的任何可选方法的默认实现。这种方法与您的“扩展”方法类似,并为您提供一些相同的专业人员。

我从未成为将类名作为字符串传递的忠实粉丝。我打赌它有一些用例,但对我来说它只是在你真的不需要的时候做出一个隐含的依赖。

答案 1 :(得分:0)

根据观察者的回答,我最终做了这样的事情:

// YourCoolService.php

class YourCoolService implements MyCoolPackageInterface {

    public function makeCool(MyCoolPackage $myCoolPackage)
    {
        return $myCoolPackage->make($this);
    }

}


// YourController.php

$output = (new YourService)->makeCool()->withInput(Input::all())->render(); 

...   

具有在Controller中看起来很漂亮的调用的优点,并且没有继承。太好了!