gpt4 book ai didi

PHP 特征 : How to circumvenient constructors or force them to be called?

转载 作者:可可西里 更新时间:2023-11-01 12:46:41 27 4
gpt4 key购买 nike

看看下面的特征:

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/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com