Bla*_*bam 7 php inheritance constructor traits
看看以下特点:
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
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,trait确保using类包含某个模型实例,并且它实现了某些方法.只要实现类不重写构造函数,这就可以工作.
所以这是我的问题:我想确保调用构造函数或更好的解决方案,这样我就可以在初始化时实例化这个模型.
请回答哪些方面多重继承以及es 多级继承.
IMS*_*SoP 11
我认为你正在努力使这个特性能够完成它不适合的工作.
特征不是多重继承的形式,而是"水平重用" - 它们通常被描述为"编译器辅助的复制和粘贴".因此,特征的作用是提供一些代码,这样您就不必手动将其复制到类中.它唯一的关系是use
语句出现的类,代码是"粘贴"的.为了帮助这个角色,它可以提出该目标类的一些基本要求,但在此之后,该特征不参与继承.
在您的示例中,您担心子类可能尝试访问$primaryModel
而不运行初始化它的构造函数代码,并且您尝试使用该特征来强制执行该操作; 但这实际上不是特质的责任.
以下类的定义Sub
完全等效:
trait Test {
public function foo() {
echo 'Hello, World!';
}
}
class ParentWithTrait {
use Test;
}
class Sub inherits ParentWithTrait {
}
Run Code Online (Sandbox Code Playgroud)
VS:
class ParentWithMethodDefinition {
public function foo() {
echo 'Hello, World!';
}
}
class Sub inherits ParentWithMethodDefinition {
}
Run Code Online (Sandbox Code Playgroud)
在任何一种情况下,类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()
}
}
Run Code Online (Sandbox Code Playgroud)
特征也可以将其构造函数标记为final,但这是要粘贴的代码的一部分,而不是使用特征的类的要求.你实际上可以使用构造函数的特征,但是然后编写一个新的构造函数,它将完全掩盖特征的版本:
trait Test {
final public function __construct() {
echo "Trait Constructor";
}
}
class Noisy {
use Test;
}
class Silent {
use Test;
public function __construct() {
// Nothing
}
}
Run Code Online (Sandbox Code Playgroud)
就性状而言,这就像买一瓶啤酒并将其倒入水槽:你要求它的代码并没有使用它,但那是你的问题.
但至关重要的是,您还可以为特征的方法添加别名,创建一个具有相同代码但具有不同名称和/或不同可见性的新方法.这意味着您可以混合来自声明构造函数的特征的代码,并在更复杂的构造函数中使用该代码,或者在类中的其他位置使用该代码.
目标类也可能使用"final + hook"模式:
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";
}
}
Run Code Online (Sandbox Code Playgroud)
这种特点还没有强制的Mixed
实施这一模式类,但它已启用它,与它促进代码重用的目的是一致的.
有趣的是,下面的代码不起作用,因为as
关键字添加别名,而不是重命名普通方法,所以这最终试图覆盖final
构造函数Mixed
:
class ChildOfMixed extends Mixed {
use TestTwo { __construct as private testTwoConstructor; }
protected function onConstruct() {
$this->testTwoConstructor();
echo "Child hook\n";
}
}
Run Code Online (Sandbox Code Playgroud)