我需要为这样的类调用实现一个系统:
想象一下,有一个类Calendar.php处理数据库查询(或者你喜欢的模型),默认情况下应该使用它。如果需要实现一些新的行为,我想实现一个类MaterialCalendar.php,它将扩展Calendar.php类,这样我就可以在新创建的MaterialCalendar.php中使用Calendar.php中的所有方法。如果需要,使用重写父方法。
问题是如何在代码中的任何位置,视图或控制器中实现这种行为:
if(子类存在){use child class} else {use default parent class}
上面伪代码中的这种行为应该是动态的,所以如果没有MaterialCalendar.php,默认情况下应该使用Calendar.php,如果存在MaterialCalendar.php那么应该使用它。它需要是动态的,与本例中使用的类名无关。
答案 0 :(得分:1)
定义接口以保证您的代码可以与ICalendar的任何实现一起使用:
interface ICalendar {
public function method1();
public function method2();
}
创建实施:
class Calendar implements ICalendar {
public function method1() {}
public function method2() {}
}
class MaterialCalendar extends Calendar {
public function method1() {}
public function method2() {}
}
简单容器
class SimpleContainer {
private static $binds = [];
public static function bind($interface, $class) {
self::$binds[$interface] = $class;
}
public static function make($interface) {
if (array_key_exists($interface, self::$binds)) {
return new self::$binds[$interface];
}
throw new \Exception("Interface is not binded");
}
}
在bootstrap的某个地方你应该确定要绑定到接口的类,如:
SimpleContainer::bind(ICalendar::class, MaterialCalendar::class);
在需要获取日历对象的所有位置使用以下代码:
SimpleContainer::make(ICalendar::class);
答案 1 :(得分:0)
Andrej开局不错,但没有必要为此目的设计容器。 Laravel附带了一个功能强大的container,您可以将实现绑定到接口。
使用Andrej的界面和具体类,您可以创建一个service provider,将所需的类绑定到ICalendar
接口:
(在提供者的注册方法中):
$this->app->bind('App\Contracts\ICalendar', 'App\Models\MaterialCalendar');
当然,在这里,您将有条件地决定将哪个类绑定到接口(请参阅函数class_exists
)。
从这一点开始,您可以依赖Laravel的容器在任何需要的位置注入此依赖项。例如,在CalendarController
的{{1}}方法中,您只需type hint 界面,Laravel将自动为您提供具体类的实例绑定它:
store
我绝对建议您阅读container以及providers上的文档。您可能感兴趣的是Contextual Binding,您可以在其中有条件地将实现绑定到接口。