1

对于一些更复杂的类层次结构,我用一个最小的例子来解决这个问题。

给出了这个类 - 可以修改方法“createOrUpdate()”:

class A {

    protected $a;
    protected $b;
    protected $c;

    function __construct($a,$b,$c) {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }

    public static function createOrUpdate($a,$b,$c) {
        if(self::exists($b)) {
            someWhateverUpdate();
        } else {
            new static($a,$b,$c);
        }
    }
}

现在让我们看看如果我们扩展它会发生什么:

class B extends A {
    function __construct($a,$b,$c) {
        parent::__construct($a,$b,$c);
    }
}
B::createOrUpdate("rock","this","now");

工作正常!

class C extends B {
    function __construct($a,$b) {
        parent::__construct($a,$b,"exactly");
    }
}
C::createOrUpdate("rock","this","now");

也可以正常工作,但是如果有人确实 createOrUpdate() 参数 $c 会默默地丢失!

class D extends A {
    protected $d;
    function __construct($a,$b,$c,$d) {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
        $this->d = $d;
    }
}
D::createOrUpdate("rock","this","now");

错误:引发ArgumentCountError

class E extends A {
        function __construct($b,$c) {
        $this->a = "Lorem";
        $this->b = $b;
        $this->c = $c;
    }
}

D::createOrUpdate("rock","this","now");

错误:有效,但行为完全出乎意料。

现在我的问题是:我可以在内部使用一些反射createOrUpdate()来检查当前调用的子类是否正确地实现了构造函数?如果其他人可以在层次结构中实现更多子类,您将如何处理?

4

3 回答 3

1

在对@nforced 的输入进行了进一步试验后,我发现了另一个很好的解决方案 - 使构造函数受保护并且是最终的。现在,子类被迫实现create()使用所需构造函数的创建方法(例如)。

class A {

    protected $a;
    protected $b;
    protected $c;

    protected final function __construct($a,$b,$c) {
        $this->a = $a;
        $this->b = $b;
        $this->c = $c;
    }

    public static function createOrUpdate($a,$b,$c) {
        if(self::exists($b)) {
            updateMe();
        } else {
            new static($a,$b,$c);
        }
    }
}
于 2018-11-13T14:59:15.187 回答
1

如果你实现你的 A 类的接口呢?

interface interfaceA {
    public function __construct($a, $b, $c);
}

class A implements interfaceA
{
 ...
}

这将强制每个扩展类要么没有构造函数,要么在 A 类上实现匹配的,否则PHP Fatal error: Declaration of B::__construct($a, $b) must be compatible with interfaceA::__construct($a, $b, $c)将被抛出。

您还可以添加public static function createOrUpdate($a, $b, $c);到接口以强制所有扩展类实现此类方法。

于 2018-11-13T14:35:45.817 回答
0

您是否尝试向upsert()函数发送对象/接口?像这样:

class Parameters {
    private $a;
    private $b;
    private $c;
    ...
    setter&getter for attributes();
}
$paramObj = new Parameters();
$paramObj->setA('a');
...

D::upsert($paramObj);

class D extends A {
    public static function upsert(Parameters $param) {
        if ($param->getA()) {
            doSth();
        } else {
            $instance = new static();
            $instance->a = $param->getB();
        }
    }
}

这只是我的一点看法,如果我错过了什么,请告诉我,谢谢。

于 2019-05-21T16:49:15.667 回答