trait PrimaryModelRest { use RestController; protected $primaryModel; public function __construct() { $mc = $this->getPrimaryModelClass(); try { $this->primaryModel = new $mc(); if(!($this->primaryModel instanceof Model)) { throw new ClassNotFoundException("Primary Model fatal exception: The given Class is not an instance of Illuminate\Database\Eloquent\Model"); } } catch (Exception $e) { throw new WrongImplementationException("Primary Model Exception: Class not found."); } } /** * @return string: Classname of the primary model. */ public abstract function getPrimaryModelClass(); // varIoUs functions here }
正如您所看到的,trait确保using类包含某个模型实例,并且它实现了某些方法.只要实现类不重写构造函数,这就可以工作.
所以这是我的问题:我想确保调用构造函数或更好的解决方案,这样我就可以在初始化时实例化这个模型.
请回答哪些方面多重继承以及es多级继承.
特征不是多重继承的形式,而是“水平重用” – 它们通常被描述为“编译器辅助的复制和粘贴”.因此,特征的作用是提供一些代码,这样您就不必手动将其复制到类中.它唯一的关系是发生use语句的类,代码是“粘贴”的.为了帮助这个角色,它可以提出该目标类的一些基本要求,但在此之后,该特征不参与继承.
在您的示例中,您担心子类可能会尝试访问$primaryModel而不运行初始化它的构造函数代码,并且您尝试使用该特征来强制执行该操作;但这实际上不是特质的责任.
Sub类的以下定义完全等效:
trait Test { public function foo() { echo 'Hello,World!'; } } class ParentWithTrait { use Test; } class Sub inherits ParentWithTrait { }
VS:
class ParentWithMethodDefinition { public function foo() { echo 'Hello,World!'; } } class Sub inherits ParentWithMethodDefinition { }
在任何一种情况下,类Sub都可以有自己的foo()定义,并绕过你在父类中编写的逻辑.
唯一可以阻止它的合约是final关键字,在你的情况下,这意味着将你的构造函数标记为final.然后,您可以提供一个可以为子类重写的扩展点,以添加它们自己的初始化:
class Base { final public function __construct() { important_things(); // Always run this! $this->onConstruct(); // Extension point } protected function onConstruct() { // empty default definition } } class Sub { protected function onConstruct() { stuff_for_sub(); // Runs after mandatory important_things() } }
特征也可以将其构造函数标记为final,但这是要粘贴的代码的一部分,而不是使用特征对类的要求.你实际上可以使用带有构造函数的特征,但是然后编写一个新的构造函数,它会完全掩盖特征的版本:
trait Test { final public function __construct() { echo "Trait Constructor"; } } class Noisy { use Test; } class Silent { use Test; public function __construct() { // Nothing } }
就性状而言,这就像买一瓶啤酒并将其倒入水槽:你要求它的代码并没有使用它,但那是你的问题.
但至关重要的是,您还可以为特征的方法添加别名,创建一个具有相同代码但具有不同名称和/或不同可见性的新方法.这意味着您可以混合来自声明构造函数的特征的代码,并在更复杂的构造函数中使用该代码,或者在类中的其他位置使用该代码.
目标类也可能使用“最终挂钩”模式:
trait TestOne { final public function __construct() { echo "Trait TestOne Constructor\n"; } } trait TestTwo { final public function __construct() { echo "Trait TestTwo Constructor\n"; } } class Mixed { final public function __construct() { echo "Beginning\n"; $this->testOneConstructor(); echo "Middle\n"; $this->testTwoConstructor(); echo "After Traits\n"; $this->onConstruct(); echo "After Sub-Class Hook\n"; } use TestOne { __construct as private testOneConstructor; } use TestTwo { __construct as private testTwoConstructor; } protected function onConstruct() { echo "Default hook\n"; } } class ChildOfMixed extends Mixed { protected function onConstruct() { echo "Child hook\n"; } }
该特性并未强制Mixed类实现此模式,但它已启用它,以实现其促进代码重用的目的.
有趣的是,下面的代码不起作用,因为as关键字添加别名,而不是重命名普通方法,所以这最终试图覆盖混合的最终构造函数:
class ChildOfMixed extends Mixed { use TestTwo { __construct as private testTwoConstructor; } protected function onConstruct() { $this->testTwoConstructor(); echo "Child hook\n"; } }