- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
看看下面的特征:
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 类拥有特定的模型实例并实现特定的方法。这只要实现类不覆盖构造函数就有效。
所以这是我的问题:我想确保调用构造函数或更好的解决方案,以便我可以在初始化时实例化此模型。
请回答尊重多重继承以及多级继承。
最佳答案
我认为您正试图让 trait 完成它不适合的工作。
Traits 不是多重继承的一种形式,而是“水平重用”——它们通常被描述为“编译器辅助的复制和粘贴”。因此,特征的工作是提供一些代码,这样您就不必手动将它复制到类中。它唯一的关系是与 use
语句出现的类,代码被“粘贴”的地方。为了帮助这个角色,它可以该目标类提出一些基本要求,但在那之后,特征不参与继承。
在您的示例中,您担心子类可能会在不运行初始化它的构造函数代码的情况下尝试访问 $primaryModel
,并且您正在尝试使用 trait 来强制执行;但这实际上不是特征的责任。
类 Sub
的以下定义是完全等价的:
trait Test {
public function foo() {
echo 'Hello, World!';
}
}
class ParentWithTrait {
use Test;
}
class Sub inherits ParentWithTrait {
}
对比:
class ParentWithMethodDefinition {
public function foo() {
echo 'Hello, World!';
}
}
class Sub inherits ParentWithMethodDefinition {
}
无论哪种情况,类 Sub
都可以有自己的 foo()
定义,并绕过您在父类中编写的逻辑。
唯一可以防止这种情况的契约(Contract)是 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()
}
}
特征也可以将其构造函数标记为最终的,但是这是被粘贴的代码的一部分,而不是对使用特征的类的要求。你实际上可以使用带有构造函数的特征,但随后也编写一个新的构造函数,它会完全屏蔽特征的版本:
trait Test {
final public function __construct() {
echo "Trait Constructor";
}
}
class Noisy {
use Test;
}
class Silent {
use Test;
public function __construct() {
// Nothing
}
}
就 trait 而言,这就像买了一瓶啤酒并将其倒进水槽:你要了它的代码却没有使用它,但那是你的问题。
不过,至关重要的是,您还可以别名 trait 的方法,创建一个具有相同代码但不同名称和/或不同可见性的新方法。这意味着您可以混入声明构造函数的特征代码,并在更复杂的构造函数或类中的其他地方使用该代码。
目标类也可能使用“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";
}
}
特征没有强制 Mixed
类实现这个模式,但是它启用它,以符合它的目的促进代码重用。
有趣的是,下面的代码不起作用,因为as
关键字添加一个别名,而不是重命名普通方法,所以这最终会尝试覆盖 Mixed
中的 final
构造函数:
class ChildOfMixed extends Mixed {
use TestTwo { __construct as private testTwoConstructor; }
protected function onConstruct() {
$this->testTwoConstructor();
echo "Child hook\n";
}
}
关于PHP 特征 : How to circumvenient constructors or force them to be called?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47269922/
我想在我的单元测试中模拟一个遗留对象。这是构造函数: public Class LegacyClass{ public LegacyClass(Object... obj) {
此处说明https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function函数对象实例的构造函数属性“指定创建对
有没有办法从子类中的构造函数分配在父类(super class)中声明的实例变量?我已经习惯使用 BUILD() 作为构造函数,但我想知道这是否是个好主意。 IE: use v6; clas
鉴于以下情况: type AStruct struct { m_Map map[int]bool } 在这种情况下,AStruct的实例在AStruct.m_Map初始化之前不能使用: m_M
我是 Android 新手,我正在尝试学习如何使用 Gson 解析 API 调用。我已经阅读了一些内容,我正在尝试遵循这个示例:http://www.javacodegeeks.com/2011/01
我正在阅读 this文章,我不知道下面这行是做什么的。即使我删除了这一行,我也看不出有什么不同。 this.constructor.prototype.constructor.apply(this,A
这个问题已经有答案了: JsonMappingException: No suitable constructor found for type [simple type, class ]: can
我正在处理我的第一个 Flutter 项目,我正在构建一个登录页面,我创建了一个变量来存储一个 TextFormFieldController,但我收到了上面的错误,因为我删除了构造函数。当我返回这个
假设我们有以下主要和次要构造函数: open class Animal(val name:String){ internal constructor(message:InputStream): t
为什么默认复制构造函数不调用 monster 的基构造函数,但是当我在 troll 中包含一个用户定义的复制构造函数时,它会调用父级(即: 怪物) 构造函数? 我认为它的工作原理如下:创建基础对象,然
这个问题在这里已经有了答案: Is there a difference between foo(void) and foo() in C++ or C? (4 个答案) 关闭 8 年前。 我注意到
我将 T4MVC 与 MVC2 一起使用。 我有以下构建 block : 一个简单的实体接口(interface),它定义了每个 POCO 实体必须有一个 long Id属性(property): p
以下代码返回一个错误: “构造函数调用必须是构造函数中的第一个语句。” 我不明白。我的代码中的构造函数是第一条语句。我究竟做错了什么? public class labelsAndIcons exte
我是 kotlin 的新手,对它包含的所有有用的语法糖和功能感到惊讶。 但是每当我声明一个构造函数时,我都必须独立地将我的所有字段设为私有(private)。 class Result(private
作为主题,相关代码为: #include class ABC { public: ABC() { std::cout<< "default con
在 Haxe 中,我创建了一个名为 的类。我的类 喜欢: class MyClass { var score: String; public function new (score:
不确定为什么会这样,尝试删除所有 new 实例,从 const ect 切换到 let。可以运行站点,但是当我通过 html 表单运行发布请求时,在“const user = new UserSche
我是 Javascript 的新手,我正在尝试深入挖掘并理解继承、构造函数和原型(prototype)链。所以,我创建了一个构造函数, var a = function(){this.integer=
我知道 JavaScript 中的函数有双重生命,第一个是函数(作为创建实例的第一类事物),第二个是普通对象。 但是我很惊讶地看到下面控制台的输出。 function A() { consol
这个问题在这里已经有了答案: Why can't I access a property of an integer with a single dot? (5 个答案) 关闭 5 年前。 为什么
我是一名优秀的程序员,十分优秀!