代码之家  ›  专栏  ›  技术社区  ›  Blackbam

PHP后期静态绑定(new static):如何确保子类构造函数的兼容性并处理不同的构造函数?

  •  0
  • Blackbam  · 技术社区  · 7 年前

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

    给定此类-方法“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");
    

    错误:抛出

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

    错误:正常工作,但行为完全出乎意料。

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

    2 回复  |  直到 7 年前
        1
  •  1
  •   nforced    7 年前

    如果你实现你的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); 以强制所有扩展类实现此类方法。

        2
  •  1
  •   Blackbam    7 年前

    在对@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);
            }
        }
    }
    
        3
  •  0
  •   Randal.Teng    7 年前

    是否尝试将对象/接口发送到 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();
            }
        }
    }
    

    这只是我的一点意见,如果我错过了什么,告诉我,谢谢。

    推荐文章